[KSPROXY]
[reactos.git] / reactos / dll / directx / ksproxy / proxy.cpp
index 5e939eb..bd34ec8 100644 (file)
@@ -8,9 +8,23 @@
  */
 #include "precomp.h"
 
+#ifndef _MSC_VER
 const GUID IID_IPersistPropertyBag = {0x37D84F60, 0x42CB, 0x11CE, {0x81, 0x35, 0x00, 0xAA, 0x00, 0x4B, 0xB8, 0x51}};
 const GUID GUID_NULL                     = {0x00000000L, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
+const GUID IID_ISpecifyPropertyPages = {0xB196B28B, 0xBAB4, 0x101A, {0xB6, 0x9C, 0x00, 0xAA, 0x00, 0x34, 0x1D, 0x07}};
+const GUID IID_IPersistStream = {0x00000109, 0x0000, 0x0000, {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}};
+const GUID KSPROPSETID_MediaSeeking = {0xEE904F0CL, 0xD09B, 0x11D0, {0xAB, 0xE9, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID KSPROPSETID_Clock = {0xDF12A4C0L, 0xAC17, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
+const GUID KSEVENTSETID_Clock = {0x364D8E20L, 0x62C7, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
+const GUID KSPROPSETID_Stream = {0x65aaba60L, 0x98ae, 0x11cf, {0xa1, 0x0d, 0x00, 0x20, 0xaf, 0xd1, 0x56, 0xe4}};
+const GUID IID_IPersist = {0x0000010c, 0x0000, 0x0000, {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}};
+#endif
+
 const GUID IID_IBDA_DeviceControl = {0xFD0A5AF3, 0xB41D, 0x11d2, {0x9C, 0x95, 0x00, 0xC0, 0x4F, 0x79, 0x71, 0xE0}};
+const GUID IID_IKsAggregateControl = {0x7F40EAC0, 0x3947, 0x11D2, {0x87, 0x4E, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID IID_IKsClockPropertySet = {0x5C5CBD84, 0xE755, 0x11D0, {0xAC, 0x18, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID IID_IKsTopology             = {0x28F54683, 0x06FD, 0x11D2, {0xB2, 0x7A, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}};
+const GUID IID_IKsClock            = {0x877E4351, 0x6FEA, 0x11D0, {0xB8, 0x63, 0x00, 0xAA, 0x00, 0xA2, 0x16, 0xA1}};
 /*
     Needs IKsClock, IKsNotifyEvent
 */
@@ -18,21 +32,20 @@ const GUID IID_IBDA_DeviceControl = {0xFD0A5AF3, 0xB41D, 0x11d2, {0x9C, 0x95, 0x
 class CKsProxy : public IBaseFilter,
                  public IAMovieSetup,
                  public IPersistPropertyBag,
-                 public IKsObject
-/*
+                 public IKsObject,
                  public IPersistStream,
+                 public IAMDeviceRemoval,
                  public ISpecifyPropertyPages,
                  public IReferenceClock,
                  public IMediaSeeking,
-                 public IKsObject,
                  public IKsPropertySet,
+                 public IKsClock,
                  public IKsClockPropertySet,
                  public IAMFilterMiscFlags,
                  public IKsControl,
                  public IKsTopology,
-                 public IKsAggregateControl,
-                 public IAMDeviceRemoval
-*/
+                 public IKsAggregateControl
+
 {
 public:
     typedef std::vector<IUnknown *>ProxyPluginVector;
@@ -50,7 +63,7 @@ public:
         InterlockedDecrement(&m_Ref);
         if (!m_Ref)
         {
-            delete this;
+            //delete this;
             return 0;
         }
         return m_Ref;
@@ -70,6 +83,64 @@ public:
     HRESULT STDMETHODCALLTYPE JoinFilterGraph(IFilterGraph *pGraph, LPCWSTR pName);
     HRESULT STDMETHODCALLTYPE QueryVendorInfo(LPWSTR *pVendorInfo);
 
+    //IReferenceClock
+    HRESULT STDMETHODCALLTYPE GetTime(REFERENCE_TIME *pTime);
+    HRESULT STDMETHODCALLTYPE AdviseTime(REFERENCE_TIME baseTime, REFERENCE_TIME streamTime, HEVENT hEvent, DWORD_PTR *pdwAdviseCookie);
+    HRESULT STDMETHODCALLTYPE AdvisePeriodic(REFERENCE_TIME startTime, REFERENCE_TIME periodTime, HSEMAPHORE hSemaphore, DWORD_PTR *pdwAdviseCookie);
+    HRESULT STDMETHODCALLTYPE Unadvise(DWORD_PTR dwAdviseCookie);
+
+    //IMediaSeeking
+    HRESULT STDMETHODCALLTYPE GetCapabilities(DWORD *pCapabilities);
+    HRESULT STDMETHODCALLTYPE CheckCapabilities(DWORD *pCapabilities);
+    HRESULT STDMETHODCALLTYPE IsFormatSupported(const GUID *pFormat);
+    HRESULT STDMETHODCALLTYPE QueryPreferredFormat(GUID *pFormat);
+    HRESULT STDMETHODCALLTYPE GetTimeFormat(GUID *pFormat);
+    HRESULT STDMETHODCALLTYPE IsUsingTimeFormat(const GUID *pFormat);
+    HRESULT STDMETHODCALLTYPE SetTimeFormat(const GUID *pFormat);
+    HRESULT STDMETHODCALLTYPE GetDuration(LONGLONG *pDuration);
+    HRESULT STDMETHODCALLTYPE GetStopPosition(LONGLONG *pStop);
+    HRESULT STDMETHODCALLTYPE GetCurrentPosition(LONGLONG *pCurrent);
+    HRESULT STDMETHODCALLTYPE ConvertTimeFormat(LONGLONG *pTarget, const GUID *pTargetFormat, LONGLONG Source, const GUID *pSourceFormat);
+    HRESULT STDMETHODCALLTYPE SetPositions(LONGLONG *pCurrent, DWORD dwCurrentFlags, LONGLONG *pStop, DWORD dwStopFlags);
+    HRESULT STDMETHODCALLTYPE GetPositions(LONGLONG *pCurrent, LONGLONG *pStop);
+    HRESULT STDMETHODCALLTYPE GetAvailable(LONGLONG *pEarliest, LONGLONG *pLatest);
+    HRESULT STDMETHODCALLTYPE SetRate(double dRate);
+    HRESULT STDMETHODCALLTYPE GetRate(double *pdRate);
+    HRESULT STDMETHODCALLTYPE GetPreroll(LONGLONG *pllPreroll);
+
+    //IKsPropertySet
+    HRESULT STDMETHODCALLTYPE Set(REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, DWORD cbPropData);
+    HRESULT STDMETHODCALLTYPE Get(REFGUID guidPropSet, DWORD dwPropID, LPVOID pInstanceData, DWORD cbInstanceData, LPVOID pPropData, DWORD cbPropData, DWORD *pcbReturned);
+    HRESULT STDMETHODCALLTYPE QuerySupported(REFGUID guidPropSet, DWORD dwPropID, DWORD *pTypeSupport);
+
+    //IAMFilterMiscFlags
+    ULONG STDMETHODCALLTYPE GetMiscFlags( void);
+
+    //IKsControl
+    HRESULT STDMETHODCALLTYPE KsProperty(PKSPROPERTY Property, ULONG PropertyLength, LPVOID PropertyData, ULONG DataLength, ULONG* BytesReturned);
+    HRESULT STDMETHODCALLTYPE KsMethod(PKSMETHOD Method, ULONG MethodLength, LPVOID MethodData, ULONG DataLength, ULONG* BytesReturned);
+    HRESULT STDMETHODCALLTYPE KsEvent(PKSEVENT Event, ULONG EventLength, LPVOID EventData, ULONG DataLength, ULONG* BytesReturned);
+
+    //IKsTopolology
+    HRESULT STDMETHODCALLTYPE CreateNodeInstance(ULONG NodeId, ULONG Flags, ACCESS_MASK DesiredAccess, IUnknown* UnkOuter, REFGUID InterfaceId, LPVOID* Interface);
+
+    //IKsAggregateControl
+    HRESULT STDMETHODCALLTYPE KsAddAggregate(IN REFGUID AggregateClass);
+    HRESULT STDMETHODCALLTYPE KsRemoveAggregate(REFGUID AggregateClass);
+
+    //IKsClockPropertySet
+    HRESULT STDMETHODCALLTYPE KsGetTime(LONGLONG* Time);
+    HRESULT STDMETHODCALLTYPE KsSetTime(LONGLONG Time);
+    HRESULT STDMETHODCALLTYPE KsGetPhysicalTime(LONGLONG* Time);
+    HRESULT STDMETHODCALLTYPE KsSetPhysicalTime(LONGLONG Time);
+    HRESULT STDMETHODCALLTYPE KsGetCorrelatedTime(KSCORRELATED_TIME* CorrelatedTime);
+    HRESULT STDMETHODCALLTYPE KsSetCorrelatedTime(KSCORRELATED_TIME* CorrelatedTime);
+    HRESULT STDMETHODCALLTYPE KsGetCorrelatedPhysicalTime(KSCORRELATED_TIME* CorrelatedTime);
+    HRESULT STDMETHODCALLTYPE KsSetCorrelatedPhysicalTime(KSCORRELATED_TIME* CorrelatedTime);
+    HRESULT STDMETHODCALLTYPE KsGetResolution(KSRESOLUTION* Resolution);
+    HRESULT STDMETHODCALLTYPE KsGetState(KSSTATE* State);
+
+
     //IAMovieSetup methods
     HRESULT STDMETHODCALLTYPE Register( void);
     HRESULT STDMETHODCALLTYPE Unregister( void);
@@ -82,8 +153,26 @@ public:
     // IKsObject
     HANDLE STDMETHODCALLTYPE KsGetObjectHandle();
 
-    CKsProxy() : m_Ref(0), m_pGraph(0), m_ReferenceClock(0), m_FilterState(State_Stopped), m_hDevice(0), m_Plugins(), m_Pins() {};
-    virtual ~CKsProxy()
+    // IKsClock
+    HANDLE STDMETHODCALLTYPE KsGetClockHandle();
+
+    //IAMDeviceRemoval
+    HRESULT STDMETHODCALLTYPE DeviceInfo(CLSID *pclsidInterfaceClass, LPWSTR *pwszSymbolicLink);
+    HRESULT STDMETHODCALLTYPE Reassociate(void);
+    HRESULT STDMETHODCALLTYPE Disassociate( void);
+
+    //IPersistStream
+    HRESULT STDMETHODCALLTYPE IsDirty( void);
+    HRESULT STDMETHODCALLTYPE Load(IStream *pStm);
+    HRESULT STDMETHODCALLTYPE Save(IStream *pStm, BOOL fClearDirty);
+    HRESULT STDMETHODCALLTYPE GetSizeMax(ULARGE_INTEGER *pcbSize);
+
+    // ISpecifyPropertyPages
+    HRESULT STDMETHODCALLTYPE GetPages(CAUUID *pPages);
+
+
+    CKsProxy();
+    ~CKsProxy()
     {
         if (m_hDevice)
             CloseHandle(m_hDevice);
@@ -95,7 +184,14 @@ public:
     HRESULT STDMETHODCALLTYPE GetPinInstanceCount(ULONG PinId, PKSPIN_CINSTANCES Instances);
     HRESULT STDMETHODCALLTYPE GetPinDataflow(ULONG PinId, KSPIN_DATAFLOW * DataFlow);
     HRESULT STDMETHODCALLTYPE GetPinName(ULONG PinId, KSPIN_DATAFLOW DataFlow, ULONG PinCount, LPWSTR * OutPinName);
+    HRESULT STDMETHODCALLTYPE GetPinCommunication(ULONG PinId, KSPIN_COMMUNICATION * Communication);
     HRESULT STDMETHODCALLTYPE CreatePins();
+    HRESULT STDMETHODCALLTYPE GetMediaSeekingFormats(PKSMULTIPLE_ITEM *FormatList);
+    HRESULT STDMETHODCALLTYPE CreateClockInstance();
+    HRESULT STDMETHODCALLTYPE PerformClockProperty(ULONG PropertyId, ULONG PropertyFlags, PVOID OutputBuffer, ULONG OutputBufferSize);
+    HRESULT STDMETHODCALLTYPE SetPinState(KSSTATE State);
+
+
 protected:
     LONG m_Ref;
     IFilterGraph *m_pGraph;
@@ -104,8 +200,26 @@ protected:
     HANDLE m_hDevice;
     ProxyPluginVector m_Plugins;
     PinVector m_Pins;
+    LPWSTR m_DevicePath;
+    CLSID m_DeviceInterfaceGUID;
+    HANDLE m_hClock;
+    CRITICAL_SECTION m_Lock;
 };
 
+CKsProxy::CKsProxy() : m_Ref(0),
+                       m_pGraph(0),
+                       m_ReferenceClock((IReferenceClock*)this),
+                       m_FilterState(State_Stopped),
+                       m_hDevice(0),
+                       m_Plugins(),
+                       m_Pins(),
+                       m_DevicePath(0),
+                       m_hClock(0)
+{
+    InitializeCriticalSection(&m_Lock);
+}
+
+
 HRESULT
 STDMETHODCALLTYPE
 CKsProxy::QueryInterface(
@@ -127,42 +241,1918 @@ CKsProxy::QueryInterface(
         reinterpret_cast<IPersistPropertyBag*>(*Output)->AddRef();
         return NOERROR;
     }
-    if (IsEqualGUID(refiid, IID_IKsObject))
+    else if (IsEqualGUID(refiid, IID_IAMDeviceRemoval))
+    {
+        *Output = (IAMDeviceRemoval*)(this);
+        reinterpret_cast<IAMDeviceRemoval*>(*Output)->AddRef();
+        return NOERROR;
+    }
+    else if (IsEqualGUID(refiid, IID_IPersistStream))
+    {
+        *Output = (IPersistStream*)(this);
+        reinterpret_cast<IPersistStream*>(*Output)->AddRef();
+        return NOERROR;
+    }
+    else if (IsEqualGUID(refiid, IID_IPersist))
+    {
+        *Output = (IPersistStream*)(this);
+        reinterpret_cast<IPersist*>(*Output)->AddRef();
+        return NOERROR;
+    }
+    else if (IsEqualGUID(refiid, IID_IKsObject))
     {
         *Output = (IKsObject*)(this);
         reinterpret_cast<IKsObject*>(*Output)->AddRef();
         return NOERROR;
     }
+    else if (IsEqualGUID(refiid, IID_IKsClock))
+    {
+        *Output = (IKsClock*)(this);
+        reinterpret_cast<IKsClock*>(*Output)->AddRef();
+        return NOERROR;
+    }
+    else if (IsEqualGUID(refiid, IID_IReferenceClock))
+    {
+        if (!m_hClock)
+        {
+            HRESULT hr = CreateClockInstance();
+            if (FAILED(hr))
+                return hr;
+        }
+
+        *Output = (IReferenceClock*)(this);
+        reinterpret_cast<IReferenceClock*>(*Output)->AddRef();
+        return NOERROR;
+    }
+    else if (IsEqualGUID(refiid, IID_IMediaSeeking))
+    {
+        *Output = (IMediaSeeking*)(this);
+        reinterpret_cast<IMediaSeeking*>(*Output)->AddRef();
+        return NOERROR;
+    }
+    else if (IsEqualGUID(refiid, IID_IAMFilterMiscFlags))
+    {
+        *Output = (IAMFilterMiscFlags*)(this);
+        reinterpret_cast<IAMFilterMiscFlags*>(*Output)->AddRef();
+        return NOERROR;
+    }
+    else if (IsEqualGUID(refiid, IID_IKsControl))
+    {
+        *Output = (IKsControl*)(this);
+        reinterpret_cast<IKsControl*>(*Output)->AddRef();
+        return NOERROR;
+    }
+    else if (IsEqualGUID(refiid, IID_IKsPropertySet))
+    {
+        *Output = (IKsPropertySet*)(this);
+        reinterpret_cast<IKsPropertySet*>(*Output)->AddRef();
+        return NOERROR;
+    }
+    else if (IsEqualGUID(refiid, IID_IKsTopology))
+    {
+        *Output = (IKsTopology*)(this);
+        reinterpret_cast<IKsTopology*>(*Output)->AddRef();
+        return NOERROR;
+    }
+    else if (IsEqualGUID(refiid, IID_IKsAggregateControl))
+    {
+        *Output = (IKsAggregateControl*)(this);
+        reinterpret_cast<IKsAggregateControl*>(*Output)->AddRef();
+        return NOERROR;
+    }
+    else if (IsEqualGUID(refiid, IID_IKsClockPropertySet))
+    {
+        if (!m_hClock)
+        {
+            HRESULT hr = CreateClockInstance();
+            if (FAILED(hr))
+                return hr;
+        }
+
+        *Output = (IKsClockPropertySet*)(this);
+        reinterpret_cast<IKsClockPropertySet*>(*Output)->AddRef();
+        return NOERROR;
+    }
+    else if (IsEqualGUID(refiid, IID_ISpecifyPropertyPages))
+    {
+        *Output = (ISpecifyPropertyPages*)(this);
+        reinterpret_cast<ISpecifyPropertyPages*>(*Output)->AddRef();
+        return NOERROR;
+    }
 
     for(ULONG Index = 0; Index < m_Plugins.size(); Index++)
     {
-        if (m_Pins[Index])
-        {
-            HRESULT hr = m_Plugins[Index]->QueryInterface(refiid, Output);
-            if (SUCCEEDED(hr))
-            {
-                WCHAR Buffer[100];
-                LPOLESTR lpstr;
-                StringFromCLSID(refiid, &lpstr);
-                swprintf(Buffer, L"CKsProxy::QueryInterface plugin %lu supports interface %s\n", Index, lpstr);
-                OutputDebugStringW(Buffer);
-                CoTaskMemFree(lpstr);
-                return hr;
-            }
-        }
+        if (m_Pins[Index])
+        {
+            HRESULT hr = m_Plugins[Index]->QueryInterface(refiid, Output);
+            if (SUCCEEDED(hr))
+            {
+#ifdef KSPROXY_TRACE
+                WCHAR Buffer[100];
+                LPOLESTR lpstr;
+                StringFromCLSID(refiid, &lpstr);
+                swprintf(Buffer, L"CKsProxy::QueryInterface plugin %lu supports interface %s\n", Index, lpstr);
+                OutputDebugStringW(Buffer);
+                CoTaskMemFree(lpstr);
+#endif
+                return hr;
+            }
+        }
+    }
+#ifdef KSPROXY_TRACE
+    WCHAR Buffer[MAX_PATH];
+    LPOLESTR lpstr;
+    StringFromCLSID(refiid, &lpstr);
+    swprintf(Buffer, L"CKsProxy::QueryInterface: NoInterface for %s !!!\n", lpstr);
+    OutputDebugStringW(Buffer);
+    CoTaskMemFree(lpstr);
+#endif
+
+    return E_NOINTERFACE;
+}
+
+//-------------------------------------------------------------------
+// ISpecifyPropertyPages
+//
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::GetPages(CAUUID *pPages)
+{
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::GetPages NotImplemented\n");
+#endif
+
+    if (!pPages)
+        return E_POINTER;
+
+    pPages->cElems = 0;
+    pPages->pElems = NULL;
+
+    return S_OK;
+}
+
+//-------------------------------------------------------------------
+// IKsClockPropertySet interface
+//
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::CreateClockInstance()
+{
+    HRESULT hr;
+    HANDLE hPin = INVALID_HANDLE_VALUE;
+    ULONG Index;
+    PIN_DIRECTION PinDir;
+    IKsObject *pObject;
+    KSCLOCK_CREATE ClockCreate;
+
+    // find output pin and handle
+    for(Index = 0; Index < m_Pins.size(); Index++)
+    {
+        //get pin
+        IPin * pin = m_Pins[Index];
+        if (!pin)
+            continue;
+
+        // get direction
+        hr = pin->QueryDirection(&PinDir);
+        if (FAILED(hr))
+            continue;
+
+        // query IKsObject interface
+        hr = pin->QueryInterface(IID_IKsObject, (void**)&pObject);
+        if (FAILED(hr))
+            continue;
+
+
+        // get pin handle
+        hPin = pObject->KsGetObjectHandle();
+
+        //release IKsObject
+        pObject->Release();
+
+        if (hPin != INVALID_HANDLE_VALUE)
+            break;
+    }
+
+    if (hPin == INVALID_HANDLE_VALUE)
+    {
+        // clock can only be instantiated on a pin handle
+        return E_NOTIMPL;
+    }
+
+    if (m_hClock)
+    {
+        // release clock handle
+        CloseHandle(m_hClock);
+    }
+
+    //setup clock create request
+    ClockCreate.CreateFlags = 0;
+
+    // setup clock create request
+    hr = KsCreateClock(hPin, &ClockCreate, &m_hClock); // FIXME KsCreateClock returns NTSTATUS
+    if (SUCCEEDED(hr))
+    {
+        // failed to create clock
+        return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
+    }
+
+    return S_OK;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::PerformClockProperty(
+    ULONG PropertyId,
+    ULONG PropertyFlags,
+    PVOID OutputBuffer,
+    ULONG OutputBufferSize)
+{
+    KSPROPERTY Property;
+    HRESULT hr;
+    ULONG BytesReturned;
+
+    if (!m_hClock)
+    {
+        // create clock
+        hr = CreateClockInstance();
+        if (FAILED(hr))
+            return hr;
+    }
+
+    // setup request
+    Property.Set = KSPROPSETID_Clock;
+    Property.Id = PropertyId;
+    Property.Flags = PropertyFlags;
+
+    hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)OutputBuffer, OutputBufferSize, &BytesReturned);
+
+    return hr;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::KsGetTime(
+    LONGLONG* Time)
+{
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::KsGetTime\n");
+#endif
+
+    return PerformClockProperty(KSPROPERTY_CLOCK_TIME, KSPROPERTY_TYPE_GET, (PVOID)Time, sizeof(LONGLONG));
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::KsSetTime(
+    LONGLONG Time)
+{
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::KsSetTime\n");
+#endif
+
+    return PerformClockProperty(KSPROPERTY_CLOCK_TIME, KSPROPERTY_TYPE_SET, (PVOID)&Time, sizeof(LONGLONG));
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::KsGetPhysicalTime(
+    LONGLONG* Time)
+{
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::KsGetPhysicalTime\n");
+#endif
+
+    return PerformClockProperty(KSPROPERTY_CLOCK_PHYSICALTIME, KSPROPERTY_TYPE_GET, (PVOID)Time, sizeof(LONGLONG));
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::KsSetPhysicalTime(
+    LONGLONG Time)
+{
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::KsSetPhysicalTime\n");
+#endif
+
+    return PerformClockProperty(KSPROPERTY_CLOCK_PHYSICALTIME, KSPROPERTY_TYPE_SET, (PVOID)&Time, sizeof(LONGLONG));
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::KsGetCorrelatedTime(
+    KSCORRELATED_TIME* CorrelatedTime)
+{
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::KsGetCorrelatedTime\n");
+#endif
+
+    return PerformClockProperty(KSPROPERTY_CLOCK_CORRELATEDTIME, KSPROPERTY_TYPE_GET, (PVOID)CorrelatedTime, sizeof(KSCORRELATED_TIME));
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::KsSetCorrelatedTime(
+    KSCORRELATED_TIME* CorrelatedTime)
+{
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::KsSetCorrelatedTime\n");
+#endif
+    return PerformClockProperty(KSPROPERTY_CLOCK_CORRELATEDTIME, KSPROPERTY_TYPE_SET, (PVOID)CorrelatedTime, sizeof(KSCORRELATED_TIME));
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::KsGetCorrelatedPhysicalTime(
+    KSCORRELATED_TIME* CorrelatedTime)
+{
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::KsGetCorrelatedPhysicalTime\n");
+#endif
+    return PerformClockProperty(KSPROPERTY_CLOCK_CORRELATEDPHYSICALTIME, KSPROPERTY_TYPE_GET, (PVOID)CorrelatedTime, sizeof(KSCORRELATED_TIME));
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::KsSetCorrelatedPhysicalTime(
+    KSCORRELATED_TIME* CorrelatedTime)
+{
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::KsSetCorrelatedPhysicalTime\n");
+#endif
+
+    return PerformClockProperty(KSPROPERTY_CLOCK_CORRELATEDPHYSICALTIME, KSPROPERTY_TYPE_SET, (PVOID)CorrelatedTime, sizeof(KSCORRELATED_TIME));
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::KsGetResolution(
+    KSRESOLUTION* Resolution)
+{
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::KsGetResolution\n");
+#endif
+    return PerformClockProperty(KSPROPERTY_CLOCK_RESOLUTION, KSPROPERTY_TYPE_GET, (PVOID)Resolution, sizeof(KSRESOLUTION));
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::KsGetState(
+    KSSTATE* State)
+{
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::KsGetState\n");
+#endif
+    return PerformClockProperty(KSPROPERTY_CLOCK_STATE, KSPROPERTY_TYPE_GET, (PVOID)State, sizeof(KSSTATE));
+}
+
+//-------------------------------------------------------------------
+// IReferenceClock interface
+//
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::GetTime(
+    REFERENCE_TIME *pTime)
+{
+    HRESULT hr;
+    KSPROPERTY Property;
+    ULONG BytesReturned;
+
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::GetTime\n");
+#endif
+
+    if (!pTime)
+        return E_POINTER;
+
+    //
+    //FIXME locks
+    //
+
+    if (!m_hClock)
+    {
+        // create clock
+        hr = CreateClockInstance();
+        if (FAILED(hr))
+            return hr;
+    }
+
+    // setup request
+    Property.Set = KSPROPSETID_Clock;
+    Property.Id = KSPROPERTY_CLOCK_TIME;
+    Property.Flags = KSPROPERTY_TYPE_GET;
+
+    // perform request
+    hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pTime, sizeof(REFERENCE_TIME), &BytesReturned);
+
+    // TODO
+    // increment value
+    //
+
+    return hr;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::AdviseTime(
+    REFERENCE_TIME baseTime,
+    REFERENCE_TIME streamTime,
+    HEVENT hEvent,
+    DWORD_PTR *pdwAdviseCookie)
+{
+    HRESULT hr;
+    KSEVENT Property;
+    ULONG BytesReturned;
+    PKSEVENT_TIME_MARK Event;
+
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::AdviseTime\n");
+#endif
+
+    //
+    //FIXME locks
+    //
+
+    if (!pdwAdviseCookie)
+        return E_POINTER;
+
+    if (!m_hClock)
+    {
+        // create clock
+        hr = CreateClockInstance();
+        if (FAILED(hr))
+            return hr;
+    }
+
+    // allocate event entry
+    Event = (PKSEVENT_TIME_MARK)CoTaskMemAlloc(sizeof(KSEVENT_TIME_MARK));
+    if (Event)
+    {
+        // setup request
+        Property.Set = KSEVENTSETID_Clock;
+        Property.Id = KSEVENT_CLOCK_POSITION_MARK;
+        Property.Flags = KSEVENT_TYPE_ENABLE;
+
+        Event->EventData.NotificationType = KSEVENTF_EVENT_HANDLE;
+        Event->EventData.EventHandle.Event = (HANDLE)hEvent;
+        Event->EventData.Alignment.Alignment[0] = 0;
+        Event->EventData.Alignment.Alignment[1] = 0;
+        Event->MarkTime = baseTime + streamTime;
+
+        // perform request
+        hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSEVENT), (PVOID)Event, sizeof(KSEVENT_TIME_MARK), &BytesReturned);
+        if (SUCCEEDED(hr))
+        {
+            // store event handle
+            *pdwAdviseCookie = (DWORD_PTR)Event;
+        }
+        else
+        {
+            // failed to enable event
+            CoTaskMemFree(Event);
+        }
+    }
+    else
+    {
+         hr = E_OUTOFMEMORY;
+    }
+
+    return hr;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::AdvisePeriodic(
+    REFERENCE_TIME startTime,
+    REFERENCE_TIME periodTime,
+    HSEMAPHORE hSemaphore,
+    DWORD_PTR *pdwAdviseCookie)
+{
+    HRESULT hr;
+    KSEVENT Property;
+    ULONG BytesReturned;
+    PKSEVENT_TIME_INTERVAL Event;
+
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::AdvisePeriodic\n");
+#endif
+
+    //
+    //FIXME locks
+    //
+
+    if (!pdwAdviseCookie)
+        return E_POINTER;
+
+    if (!m_hClock)
+    {
+        // create clock
+        hr = CreateClockInstance();
+        if (FAILED(hr))
+            return hr;
+    }
+
+    // allocate event entry
+    Event = (PKSEVENT_TIME_INTERVAL)CoTaskMemAlloc(sizeof(KSEVENT_TIME_INTERVAL));
+    if (Event)
+    {
+        // setup request
+        Property.Set = KSEVENTSETID_Clock;
+        Property.Id = KSEVENT_CLOCK_INTERVAL_MARK;
+        Property.Flags = KSEVENT_TYPE_ENABLE;
+
+        Event->EventData.NotificationType = KSEVENTF_SEMAPHORE_HANDLE;
+        Event->EventData.SemaphoreHandle.Semaphore = (HANDLE)hSemaphore;
+        Event->EventData.SemaphoreHandle.Reserved = 0;
+        Event->EventData.SemaphoreHandle.Adjustment = 1;
+        Event->TimeBase = startTime;
+        Event->Interval = periodTime;
+
+        // perform request
+        hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_ENABLE_EVENT, (PVOID)&Property, sizeof(KSEVENT), (PVOID)Event, sizeof(KSEVENT_TIME_INTERVAL), &BytesReturned);
+        if (SUCCEEDED(hr))
+        {
+            // store event handle
+            *pdwAdviseCookie = (DWORD_PTR)Event;
+        }
+        else
+        {
+            // failed to enable event
+            CoTaskMemFree(Event);
+        }
+    }
+    else
+    {
+         hr = E_OUTOFMEMORY;
+    }
+
+    return hr;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::Unadvise(
+    DWORD_PTR dwAdviseCookie)
+{
+    HRESULT hr;
+    ULONG BytesReturned;
+
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::Unadvise\n");
+#endif
+
+    if (m_hClock)
+    {
+        //lets disable the event
+        hr = KsSynchronousDeviceControl(m_hClock, IOCTL_KS_DISABLE_EVENT, (PVOID)dwAdviseCookie, sizeof(KSEVENTDATA), 0, 0, &BytesReturned);
+        if (SUCCEEDED(hr))
+        {
+            // lets free event data
+            CoTaskMemFree((LPVOID)dwAdviseCookie);
+        }
+    }
+    else
+    {
+        // no clock available
+        hr = E_FAIL;
+    }
+
+    return hr;
+}
+
+//-------------------------------------------------------------------
+// IMediaSeeking interface
+//
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::GetCapabilities(
+    DWORD *pCapabilities)
+{
+    KSPROPERTY Property;
+    ULONG BytesReturned, Index;
+    HRESULT hr = S_OK;
+    DWORD TempCaps;
+
+    Property.Set = KSPROPSETID_MediaSeeking;
+    Property.Id = KSPROPERTY_MEDIASEEKING_CAPABILITIES;
+    Property.Flags = KSPROPERTY_TYPE_GET;
+
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::GetCapabilities\n");
+#endif
+
+
+    if (!pCapabilities)
+        return E_POINTER;
+
+
+    *pCapabilities = (KS_SEEKING_CanSeekAbsolute | KS_SEEKING_CanSeekForwards | KS_SEEKING_CanSeekBackwards | KS_SEEKING_CanGetCurrentPos |
+                      KS_SEEKING_CanGetStopPos | KS_SEEKING_CanGetDuration | KS_SEEKING_CanPlayBackwards);
+
+    KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&pCapabilities, sizeof(KS_SEEKING_CAPABILITIES), &BytesReturned);
+    // check if plugins support it
+    for(Index = 0; Index < m_Plugins.size(); Index++)
+    {
+        // get plugin
+        IUnknown * Plugin = m_Plugins[Index];
+
+        if (!Plugin)
+           continue;
+
+        // query for IMediaSeeking interface
+        IMediaSeeking *pSeek = NULL;
+        hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
+        if (FAILED(hr))
+        {
+            *pCapabilities = 0;
+            return hr;
+        }
+
+        TempCaps = 0;
+        // set time format
+        hr = pSeek->GetCapabilities(&TempCaps);
+        if (SUCCEEDED(hr))
+        {
+            // and with supported flags
+            *pCapabilities = (*pCapabilities & TempCaps);
+        }
+        // release IMediaSeeking interface
+        pSeek->Release();
+    }
+    return hr;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::CheckCapabilities(
+    DWORD *pCapabilities)
+{
+    DWORD Capabilities;
+    HRESULT hr;
+
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::CheckCapabilities\n");
+#endif
+
+    if (!pCapabilities)
+        return E_POINTER;
+
+    if (!*pCapabilities)
+        return E_FAIL;
+
+    hr = GetCapabilities(&Capabilities);
+    if (SUCCEEDED(hr))
+    {
+        if ((Capabilities | *pCapabilities) == Capabilities)
+        {
+            // all present
+            return S_OK;
+        }
+
+        Capabilities = (Capabilities & *pCapabilities);
+        if (Capabilities)
+        {
+            // not all present
+            *pCapabilities = Capabilities;
+            return S_FALSE;
+        }
+        // no capabilities are present
+        return E_FAIL;
+    }
+
+    return hr;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::GetMediaSeekingFormats(
+    PKSMULTIPLE_ITEM *FormatList)
+{
+    KSPROPERTY Property;
+    HRESULT hr;
+    ULONG BytesReturned;
+
+    Property.Set = KSPROPSETID_MediaSeeking;
+    Property.Id = KSPROPERTY_MEDIASEEKING_FORMATS;
+    Property.Flags = KSPROPERTY_TYPE_GET;
+
+    // query for format size list
+    hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), NULL, 0, &BytesReturned);
+
+    if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_MORE_DATA))
+    {
+        // allocate format list
+        *FormatList = (PKSMULTIPLE_ITEM)CoTaskMemAlloc(BytesReturned);
+        if (!*FormatList)
+        {
+            // not enough memory
+            return E_OUTOFMEMORY;
+        }
+
+        // get format list
+        hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)*FormatList, BytesReturned, &BytesReturned);
+        if (FAILED(hr))
+        {
+            // failed to query format list
+            CoTaskMemFree(FormatList);
+        }
+    }
+    return hr;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::IsFormatSupported(
+    const GUID *pFormat)
+{
+    PKSMULTIPLE_ITEM FormatList;
+    LPGUID pGuid;
+    ULONG Index;
+    HRESULT hr = S_FALSE;
+
+#ifdef KSPROXY_TRACE
+    WCHAR Buffer[100];
+    LPOLESTR pstr;
+    StringFromCLSID(*pFormat, &pstr);
+    swprintf(Buffer, L"CKsProxy::IsFormatSupported %s\n",pstr);
+    OutputDebugStringW(Buffer);
+#endif
+
+    if (!pFormat)
+        return E_POINTER;
+
+    // get media formats
+    hr = GetMediaSeekingFormats(&FormatList);
+    if (SUCCEEDED(hr))
+    {
+#ifdef KSPROXY_TRACE
+        swprintf(Buffer, L"CKsProxy::IsFormatSupported NumFormat %lu\n",FormatList->Count);
+        OutputDebugStringW(Buffer);
+#endif
+
+        //iterate through format list
+        pGuid = (LPGUID)(FormatList + 1);
+        for(Index = 0; Index < FormatList->Count; Index++)
+        {
+            if (IsEqualGUID(*pGuid, *pFormat))
+            {
+                CoTaskMemFree(FormatList);
+                return S_OK;
+            }
+            pGuid++;
+        }
+        // free format list
+        CoTaskMemFree(FormatList);
+    }
+
+    // check if all plugins support it
+    for(Index = 0; Index < m_Plugins.size(); Index++)
+    {
+        // get plugin
+        IUnknown * Plugin = m_Plugins[Index];
+
+        if (!Plugin)
+            continue;
+
+        // query for IMediaSeeking interface
+        IMediaSeeking *pSeek = NULL;
+        hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
+        if (FAILED(hr))
+        {
+            // plugin does not support interface
+            hr = S_FALSE;
+#ifdef KSPROXY_TRACE
+            OutputDebugStringW(L"CKsProxy::IsFormatSupported plugin does not support IMediaSeeking interface\n");
+#endif
+            break;
+        }
+
+        // query if it is supported
+        hr = pSeek->IsFormatSupported(pFormat);
+        // release interface
+        pSeek->Release();
+
+        if (FAILED(hr) || hr == S_FALSE)
+            break;
+    }
+
+    return hr;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::QueryPreferredFormat(
+    GUID *pFormat)
+{
+    PKSMULTIPLE_ITEM FormatList;
+    HRESULT hr;
+    ULONG Index;
+
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::QueryPreferredFormat\n");
+#endif
+
+    if (!pFormat)
+        return E_POINTER;
+
+    hr = GetMediaSeekingFormats(&FormatList);
+    if (SUCCEEDED(hr))
+    {
+        if (FormatList->Count)
+        {
+            CopyMemory(pFormat, (FormatList + 1), sizeof(GUID));
+            CoTaskMemFree(FormatList);
+            return S_OK;
+        }
+        CoTaskMemFree(FormatList);
+    }
+    if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
+    {
+        // check if plugins support it
+        for(Index = 0; Index < m_Plugins.size(); Index++)
+        {
+            // get plugin
+            IUnknown * Plugin = m_Plugins[Index];
+
+            if (!Plugin)
+               continue;
+
+            // query for IMediaSeeking interface
+            IMediaSeeking *pSeek = NULL;
+            hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
+            if (SUCCEEDED(hr))
+            {
+                // get preferred time format
+                hr = pSeek->QueryPreferredFormat(pFormat);
+                // release IMediaSeeking interface
+                pSeek->Release();
+
+                if (hr != S_FALSE)
+                    return hr;
+            }
+        }
+        hr = S_FALSE;
+    }
+
+    return hr;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::GetTimeFormat(
+    GUID *pFormat)
+{
+    KSPROPERTY Property;
+    ULONG BytesReturned, Index;
+    HRESULT hr;
+
+    Property.Set = KSPROPSETID_MediaSeeking;
+    Property.Id = KSPROPERTY_MEDIASEEKING_TIMEFORMAT;
+    Property.Flags = KSPROPERTY_TYPE_GET;
+
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::GetTimeFormat\n");
+#endif
+
+    hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pFormat, sizeof(GUID), &BytesReturned);
+    if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
+    {
+        // check if plugins support it
+        for(Index = 0; Index < m_Plugins.size(); Index++)
+        {
+            hr = E_NOTIMPL;
+            // get plugin
+            IUnknown * Plugin = m_Plugins[Index];
+
+            if (!Plugin)
+               continue;
+
+            // query for IMediaSeeking interface
+            IMediaSeeking *pSeek = NULL;
+            hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
+            if (SUCCEEDED(hr))
+            {
+                // set time format
+                hr = pSeek->GetTimeFormat(pFormat);
+                // release IMediaSeeking interface
+                pSeek->Release();
+
+                if (hr != S_FALSE)
+                    break;
+            }
+        }
+    }
+    return hr;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::IsUsingTimeFormat(
+    const GUID *pFormat)
+{
+    GUID Format;
+
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::IsUsingTimeFormat\n");
+#endif
+
+    if (FAILED(QueryPreferredFormat(&Format)))
+        return S_FALSE;
+
+    if (IsEqualGUID(Format, *pFormat))
+        return S_OK;
+    else
+        return S_FALSE;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::SetTimeFormat(
+    const GUID *pFormat)
+{
+    KSPROPERTY Property;
+    ULONG BytesReturned, Index;
+    HRESULT hr;
+
+    Property.Set = KSPROPSETID_MediaSeeking;
+    Property.Id = KSPROPERTY_MEDIASEEKING_TIMEFORMAT;
+    Property.Flags = KSPROPERTY_TYPE_SET;
+
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::SetTimeFormat\n");
+#endif
+
+    hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pFormat, sizeof(GUID), &BytesReturned);
+    if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
+    {
+        // check if plugins support it
+        for(Index = 0; Index < m_Plugins.size(); Index++)
+        {
+            hr = E_NOTIMPL;
+            // get plugin
+            IUnknown * Plugin = m_Plugins[Index];
+
+            if (!Plugin)
+               continue;
+
+            // query for IMediaSeeking interface
+            IMediaSeeking *pSeek = NULL;
+            hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
+            if (FAILED(hr))
+            {
+                //not supported
+                break;
+            }
+            // set time format
+            hr = pSeek->SetTimeFormat(pFormat);
+            // release IMediaSeeking interface
+            pSeek->Release();
+
+            if (FAILED(hr))
+                break;
+        }
+    }
+    return hr;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::GetDuration(
+    LONGLONG *pDuration)
+{
+    KSPROPERTY Property;
+    ULONG BytesReturned, Index;
+    HRESULT hr;
+
+    Property.Set = KSPROPSETID_MediaSeeking;
+    Property.Id = KSPROPERTY_MEDIASEEKING_DURATION;
+    Property.Flags = KSPROPERTY_TYPE_GET;
+
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::GetDuration\n");
+#endif
+
+    hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pDuration, sizeof(LONGLONG), &BytesReturned);
+    if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
+    {
+        // check if plugins support it
+        for(Index = 0; Index < m_Plugins.size(); Index++)
+        {
+            hr = E_NOTIMPL;
+            // get plugin
+            IUnknown * Plugin = m_Plugins[Index];
+
+            if (!Plugin)
+               continue;
+
+            // query for IMediaSeeking interface
+            IMediaSeeking *pSeek = NULL;
+            hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
+            if (SUCCEEDED(hr))
+            {
+                // get duration
+                hr = pSeek->GetStopPosition(pDuration);
+                // release IMediaSeeking interface
+                pSeek->Release();
+
+                if (hr != S_FALSE) // plugin implements it
+                     break;
+            }
+        }
+    }
+    return hr;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::GetStopPosition(
+    LONGLONG *pStop)
+{
+    KSPROPERTY Property;
+    ULONG BytesReturned, Index;
+    HRESULT hr;
+
+    Property.Set = KSPROPSETID_MediaSeeking;
+    Property.Id = KSPROPERTY_MEDIASEEKING_STOPPOSITION;
+    Property.Flags = KSPROPERTY_TYPE_GET;
+
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::GetStopPosition\n");
+#endif
+
+    hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pStop, sizeof(LONGLONG), &BytesReturned);
+    if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
+    {
+        // check if plugins support it
+        for(Index = 0; Index < m_Plugins.size(); Index++)
+        {
+            hr = E_NOTIMPL;
+            // get plugin
+            IUnknown * Plugin = m_Plugins[Index];
+
+            if (!Plugin)
+               continue;
+
+            // query for IMediaSeeking interface
+            IMediaSeeking *pSeek = NULL;
+            hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
+            if (SUCCEEDED(hr))
+            {
+                // get stop position
+                hr = pSeek->GetStopPosition(pStop);
+                // release IMediaSeeking interface
+                pSeek->Release();
+
+                if (hr != S_FALSE) // plugin implements it
+                     break;
+            }
+        }
+    }
+    return hr;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::GetCurrentPosition(
+    LONGLONG *pCurrent)
+{
+    KSPROPERTY Property;
+    ULONG BytesReturned, Index;
+    HRESULT hr;
+
+    Property.Set = KSPROPSETID_MediaSeeking;
+    Property.Id = KSPROPERTY_MEDIASEEKING_POSITION;
+    Property.Flags = KSPROPERTY_TYPE_GET;
+
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::GetCurrentPosition\n");
+#endif
+
+    hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pCurrent, sizeof(LONGLONG), &BytesReturned);
+    if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
+    {
+        // check if plugins support it
+        for(Index = 0; Index < m_Plugins.size(); Index++)
+        {
+            hr = E_NOTIMPL;
+            // get plugin
+            IUnknown * Plugin = m_Plugins[Index];
+
+            if (!Plugin)
+               continue;
+
+            // query for IMediaSeeking interface
+            IMediaSeeking *pSeek = NULL;
+            hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
+            if (SUCCEEDED(hr))
+            {
+                // get current position
+                hr = pSeek->GetCurrentPosition(pCurrent);
+                // release IMediaSeeking interface
+                pSeek->Release();
+
+                if (hr != S_FALSE) // plugin implements it
+                     break;
+            }
+        }
+    }
+    return hr;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::ConvertTimeFormat(
+    LONGLONG *pTarget,
+    const GUID *pTargetFormat,
+    LONGLONG Source,
+    const GUID *pSourceFormat)
+{
+    KSP_TIMEFORMAT Property;
+    ULONG BytesReturned, Index;
+    GUID SourceFormat, TargetFormat;
+    HRESULT hr;
+
+    Property.Property.Set = KSPROPSETID_MediaSeeking;
+    Property.Property.Id = KSPROPERTY_MEDIASEEKING_CONVERTTIMEFORMAT;
+    Property.Property.Flags = KSPROPERTY_TYPE_GET;
+
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::ConvertTimeFormat\n");
+#endif
+
+    if (!pTargetFormat)
+    {
+        // get current format
+        hr = GetTimeFormat(&TargetFormat);
+        if (FAILED(hr))
+            return hr;
+
+        pTargetFormat = &TargetFormat;
+    }
+
+    if (!pSourceFormat)
+    {
+        // get current format
+        hr = GetTimeFormat(&SourceFormat);
+        if (FAILED(hr))
+            return hr;
+
+        pSourceFormat = &SourceFormat;
+    }
+
+    Property.SourceFormat = *pSourceFormat;
+    Property.TargetFormat = *pTargetFormat;
+    Property.Time = Source;
+
+
+    hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_TIMEFORMAT), (PVOID)pTarget, sizeof(LONGLONG), &BytesReturned);
+    if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
+    {
+        //default error
+        hr = E_NOTIMPL;
+
+        // check if plugins support it
+        for(Index = 0; Index < m_Plugins.size(); Index++)
+        {
+            // get plugin
+            IUnknown * Plugin = m_Plugins[Index];
+
+            if (!Plugin)
+               continue;
+
+            // query for IMediaSeeking interface
+            IMediaSeeking *pSeek = NULL;
+            hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
+            if (SUCCEEDED(hr))
+            {
+                // convert time format
+                hr = pSeek->ConvertTimeFormat(pTarget, pTargetFormat, Source, pSourceFormat);
+                // release IMediaSeeking interface
+                pSeek->Release();
+
+                if (hr != S_FALSE) // plugin implements it
+                     break;
+            }
+        }
+    }
+
+    return hr;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::SetPositions(
+    LONGLONG *pCurrent,
+    DWORD dwCurrentFlags,
+    LONGLONG *pStop,
+    DWORD dwStopFlags)
+{
+    KSPROPERTY Property;
+    KSPROPERTY_POSITIONS Positions;
+    ULONG BytesReturned, Index;
+    HRESULT hr;
+
+    Property.Set = KSPROPSETID_MediaSeeking;
+    Property.Id = KSPROPERTY_MEDIASEEKING_POSITIONS;
+    Property.Flags = KSPROPERTY_TYPE_SET;
+
+    Positions.Current = *pCurrent;
+    Positions.CurrentFlags = (KS_SEEKING_FLAGS)dwCurrentFlags;
+    Positions.Stop = *pStop;
+    Positions.StopFlags = (KS_SEEKING_FLAGS)dwStopFlags;
+
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::SetPositions\n");
+#endif
+
+    hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&Positions, sizeof(KSPROPERTY_POSITIONS), &BytesReturned);
+    if (SUCCEEDED(hr))
+    {
+        if (dwCurrentFlags & AM_SEEKING_ReturnTime)
+        {
+            // retrieve current position
+            hr = GetCurrentPosition(pCurrent);
+        }
+
+        if (SUCCEEDED(hr))
+        {
+            if (dwStopFlags & AM_SEEKING_ReturnTime)
+            {
+                // retrieve current position
+                hr = GetStopPosition(pStop);
+            }
+        }
+        return hr;
+    }
+    if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
+    {
+        hr = E_NOTIMPL;
+
+        // check if plugins support it
+        for(Index = 0; Index < m_Plugins.size(); Index++)
+        {
+            // get plugin
+            IUnknown * Plugin = m_Plugins[Index];
+
+            if (!Plugin)
+               continue;
+
+            // query for IMediaSeeking interface
+            IMediaSeeking *pSeek = NULL;
+            hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
+            if (SUCCEEDED(hr))
+            {
+                // set positions
+                hr = pSeek->SetPositions(pCurrent, dwCurrentFlags, pStop, dwStopFlags);
+                // release IMediaSeeking interface
+                pSeek->Release();
+
+                if (FAILED(hr))
+                    break;
+            }
+        }
+    }
+
+    return hr;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::GetPositions(
+    LONGLONG *pCurrent,
+    LONGLONG *pStop)
+{
+    HRESULT hr;
+
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::GetPositions\n");
+#endif
+
+    hr = GetCurrentPosition(pCurrent);
+    if (SUCCEEDED(hr))
+        hr = GetStopPosition(pStop);
+
+    return hr;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::GetAvailable(
+    LONGLONG *pEarliest,
+    LONGLONG *pLatest)
+{
+    KSPROPERTY Property;
+    KSPROPERTY_MEDIAAVAILABLE Media;
+    ULONG BytesReturned, Index;
+    HRESULT hr;
+
+    Property.Set = KSPROPSETID_MediaSeeking;
+    Property.Id = KSPROPERTY_MEDIASEEKING_AVAILABLE;
+    Property.Flags = KSPROPERTY_TYPE_GET;
+
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::GetAvailable\n");
+#endif
+
+    hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&Media, sizeof(KSPROPERTY_MEDIAAVAILABLE), &BytesReturned);
+    if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
+    {
+        // check if plugins support it
+        for(Index = 0; Index < m_Plugins.size(); Index++)
+        {
+            hr = E_NOTIMPL;
+            // get plugin
+            IUnknown * Plugin = m_Plugins[Index];
+
+            if (!Plugin)
+               continue;
+
+            // query for IMediaSeeking interface
+            IMediaSeeking *pSeek = NULL;
+            hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
+            if (SUCCEEDED(hr))
+            {
+                // delegate call
+                hr = pSeek->GetAvailable(pEarliest, pLatest);
+                // release IMediaSeeking interface
+                pSeek->Release();
+
+                if (hr != S_FALSE) // plugin implements it
+                     break;
+            }
+        }
+    }
+    else if (SUCCEEDED(hr))
+    {
+        *pEarliest = Media.Earliest;
+        *pLatest = Media.Latest;
+    }
+
+    return hr;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::SetRate(
+    double dRate)
+{
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::SetRate\n");
+#endif
+    return E_NOTIMPL;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::GetRate(
+    double *pdRate)
+{
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::GetRate\n");
+#endif
+    return E_NOTIMPL;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::GetPreroll(
+    LONGLONG *pllPreroll)
+{
+    KSPROPERTY Property;
+    ULONG BytesReturned, Index;
+    HRESULT hr;
+
+    Property.Set = KSPROPSETID_MediaSeeking;
+    Property.Id = KSPROPERTY_MEDIASEEKING_PREROLL;
+    Property.Flags = KSPROPERTY_TYPE_GET;
+
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::GetPreroll\n");
+#endif
+
+    hr = KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)pllPreroll, sizeof(LONGLONG), &BytesReturned);
+    if (hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND) || hr == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND))
+    {
+        // check if all plugins support it
+        for(Index = 0; Index < m_Plugins.size(); Index++)
+        {
+            // get plugin
+            IUnknown * Plugin = m_Plugins[Index];
+
+            if (!Plugin)
+               continue;
+
+            // query for IMediaSeeking interface
+            IMediaSeeking *pSeek = NULL;
+            hr = Plugin->QueryInterface(IID_IMediaSeeking, (void**)&pSeek);
+            if (SUCCEEDED(hr))
+            {
+                // get preroll
+                hr = pSeek->GetPreroll(pllPreroll);
+                // release IMediaSeeking interface
+                pSeek->Release();
+
+                if (hr != S_FALSE) // plugin implements it
+                     break;
+            }
+        }
+        hr = E_NOTIMPL;
+    }
+    return hr;
+}
+
+//-------------------------------------------------------------------
+// IAMFilterMiscFlags interface
+//
+
+ULONG
+STDMETHODCALLTYPE
+CKsProxy::GetMiscFlags()
+{
+    ULONG Index;
+    ULONG Flags = 0;
+    HRESULT hr;
+    PIN_DIRECTION PinDirection;
+    KSPIN_COMMUNICATION Communication;
+
+
+    for(Index = 0; Index < m_Pins.size(); Index++)
+    {
+        // get current pin
+        IPin * pin = m_Pins[Index];
+        // query direction
+        hr = pin->QueryDirection(&PinDirection);
+        if (SUCCEEDED(hr))
+        {
+            if (PinDirection == PINDIR_INPUT)
+            {
+                if (SUCCEEDED(GetPinCommunication(Index, //FIXME verify PinId
+                                        &Communication)))
+                {
+                    if (Communication != KSPIN_COMMUNICATION_NONE && Communication != KSPIN_COMMUNICATION_BRIDGE)
+                    {
+                        Flags |= AM_FILTER_MISC_FLAGS_IS_SOURCE;
+                    }
+                }
+            }
+        }
+    }
+
+#ifdef KSPROXY_TRACE
+    WCHAR Buffer[100];
+    swprintf(Buffer, L"CKsProxy::GetMiscFlags stub Flags %x\n", Flags);
+    OutputDebugStringW(Buffer);
+#endif
+
+    return Flags;
+}
+
+//-------------------------------------------------------------------
+// IKsControl
+//
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::KsProperty(
+    PKSPROPERTY Property,
+    ULONG PropertyLength,
+    LPVOID PropertyData,
+    ULONG DataLength,
+    ULONG* BytesReturned)
+{
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::KsProperty\n");
+#endif
+
+    assert(m_hDevice != 0);
+    return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)Property, PropertyLength, (PVOID)PropertyData, DataLength, BytesReturned);
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::KsMethod(
+    PKSMETHOD Method,
+    ULONG MethodLength,
+    LPVOID MethodData,
+    ULONG DataLength,
+    ULONG* BytesReturned)
+{
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::KsMethod\n");
+#endif
+
+    assert(m_hDevice != 0);
+    return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_METHOD, (PVOID)Method, MethodLength, (PVOID)MethodData, DataLength, BytesReturned);
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::KsEvent(
+    PKSEVENT Event,
+    ULONG EventLength,
+    LPVOID EventData,
+    ULONG DataLength,
+    ULONG* BytesReturned)
+{
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::KsEvent\n");
+#endif
+
+    assert(m_hDevice != 0);
+    if (EventLength)
+        return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_ENABLE_EVENT, (PVOID)Event, EventLength, (PVOID)EventData, DataLength, BytesReturned);
+    else
+        return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_DISABLE_EVENT, (PVOID)Event, EventLength, NULL, 0, BytesReturned);
+}
+
+
+//-------------------------------------------------------------------
+// IKsPropertySet
+//
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::Set(
+    REFGUID guidPropSet,
+    DWORD dwPropID,
+    LPVOID pInstanceData,
+    DWORD cbInstanceData,
+    LPVOID pPropData,
+    DWORD cbPropData)
+{
+    ULONG BytesReturned;
+
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::Set\n");
+#endif
+
+    if (cbInstanceData)
+    {
+        PKSPROPERTY Property = (PKSPROPERTY)CoTaskMemAlloc(sizeof(KSPROPERTY) + cbInstanceData);
+        if (!Property)
+            return E_OUTOFMEMORY;
+
+        Property->Set = guidPropSet;
+        Property->Id = dwPropID;
+        Property->Flags = KSPROPERTY_TYPE_SET;
+
+        CopyMemory((Property+1), pInstanceData, cbInstanceData);
+
+        HRESULT hr = KsProperty(Property, sizeof(KSPROPERTY) + cbInstanceData, pPropData, cbPropData, &BytesReturned);
+        CoTaskMemFree(Property);
+        return hr;
+    }
+    else
+    {
+        KSPROPERTY Property;
+
+        Property.Set = guidPropSet;
+        Property.Id = dwPropID;
+        Property.Flags = KSPROPERTY_TYPE_SET;
+
+        HRESULT hr = KsProperty(&Property, sizeof(KSPROPERTY), pPropData, cbPropData, &BytesReturned);
+        return hr;
+    }
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::Get(
+    REFGUID guidPropSet,
+    DWORD dwPropID,
+    LPVOID pInstanceData,
+    DWORD cbInstanceData,
+    LPVOID pPropData,
+    DWORD cbPropData,
+    DWORD *pcbReturned)
+{
+    ULONG BytesReturned;
+
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::Get\n");
+#endif
+
+    if (cbInstanceData)
+    {
+        PKSPROPERTY Property = (PKSPROPERTY)CoTaskMemAlloc(sizeof(KSPROPERTY) + cbInstanceData);
+        if (!Property)
+            return E_OUTOFMEMORY;
+
+        Property->Set = guidPropSet;
+        Property->Id = dwPropID;
+        Property->Flags = KSPROPERTY_TYPE_GET;
+
+        CopyMemory((Property+1), pInstanceData, cbInstanceData);
+
+        HRESULT hr = KsProperty(Property, sizeof(KSPROPERTY) + cbInstanceData, pPropData, cbPropData, &BytesReturned);
+        CoTaskMemFree(Property);
+        return hr;
+    }
+    else
+    {
+        KSPROPERTY Property;
+
+        Property.Set = guidPropSet;
+        Property.Id = dwPropID;
+        Property.Flags = KSPROPERTY_TYPE_GET;
+
+        HRESULT hr = KsProperty(&Property, sizeof(KSPROPERTY), pPropData, cbPropData, &BytesReturned);
+        return hr;
+    }
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::QuerySupported(
+    REFGUID guidPropSet,
+    DWORD dwPropID,
+    DWORD *pTypeSupport)
+{
+    KSPROPERTY Property;
+    ULONG BytesReturned;
+
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::QuerySupported\n");
+#endif
+
+    Property.Set = guidPropSet;
+    Property.Id = dwPropID;
+    Property.Flags = KSPROPERTY_TYPE_SETSUPPORT;
+
+    return KsProperty(&Property, sizeof(KSPROPERTY), pTypeSupport, sizeof(DWORD), &BytesReturned);
+}
+
+
+//-------------------------------------------------------------------
+// IKsTopology interface
+//
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::CreateNodeInstance(
+    ULONG NodeId,
+    ULONG Flags,
+    ACCESS_MASK DesiredAccess,
+    IUnknown* UnkOuter,
+    REFGUID InterfaceId,
+    LPVOID* Interface)
+{
+    HRESULT hr;
+
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::CreateNodeInstance\n");
+#endif
+
+    *Interface = NULL;
+
+    if (IsEqualIID(IID_IUnknown, InterfaceId) || !UnkOuter)
+    {
+        hr = CKsNode_Constructor(UnkOuter, m_hDevice, NodeId, DesiredAccess, InterfaceId, Interface);
+    }
+    else
+    {
+        // interface not supported
+        hr = E_NOINTERFACE;
+    }
+
+    return hr;
+}
+
+//-------------------------------------------------------------------
+// IKsAggregateControl interface
+//
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::KsAddAggregate(
+    IN REFGUID AggregateClass)
+{
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::KsAddAggregate NotImplemented\n");
+#endif
+    return E_NOTIMPL;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::KsRemoveAggregate(
+    REFGUID AggregateClass)
+{
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::KsRemoveAggregate NotImplemented\n");
+#endif
+
+    return E_NOTIMPL;
+}
+
+
+//-------------------------------------------------------------------
+// IPersistStream interface
+//
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::IsDirty()
+{
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::IsDirty Notimplemented\n");
+    DebugBreak();
+#endif
+    return E_NOTIMPL;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::Load(
+    IStream *pStm)
+{
+    HRESULT hr;
+    WCHAR Buffer[1000];
+    AM_MEDIA_TYPE MediaType;
+    ULONG BytesReturned;
+    LONG Length;
+
+    ULONG PinId;
+    LPOLESTR pMajor, pSub, pFormat;
+
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::Load\n");
+#endif
+
+#if 0
+    ULONG Version = ReadInt(pStm, hr);
+    if (Version != 1)
+        return E_FAIL;
+#endif
+
+    hr = pStm->Read(&Length, sizeof(ULONG), &BytesReturned);
+    swprintf(Buffer, L"Length hr %x hr length %lu\n", hr, Length);
+    OutputDebugStringW(Buffer);
+
+    do
+    {
+        hr = pStm->Read(&PinId, sizeof(ULONG), &BytesReturned);
+        swprintf(Buffer, L"Read: hr %08x PinId %lx BytesReturned %lu\n", hr, PinId, BytesReturned);
+        OutputDebugStringW(Buffer);
+
+        if (FAILED(hr) || !BytesReturned)
+            break;
+
+        Length -= BytesReturned;
+
+        hr = pStm->Read(&MediaType, sizeof(AM_MEDIA_TYPE), &BytesReturned);
+        if (FAILED(hr) || BytesReturned != sizeof(AM_MEDIA_TYPE))
+        {
+            swprintf(Buffer, L"Read failed with %lx\n", hr);
+            OutputDebugStringW(Buffer);
+            break;
+        }
+
+
+        StringFromIID(MediaType.majortype, &pMajor);
+        StringFromIID(MediaType.subtype , &pSub);
+        StringFromIID(MediaType.formattype, &pFormat);
+
+        swprintf(Buffer, L"BytesReturned %lu majortype %s subtype %s bFixedSizeSamples %u bTemporalCompression %u lSampleSize %u formattype %s, pUnk %p cbFormat %u pbFormat %p\n", BytesReturned, pMajor, pSub, MediaType.bFixedSizeSamples, MediaType.bTemporalCompression, MediaType.lSampleSize, pFormat, MediaType.pUnk, MediaType.cbFormat, MediaType.pbFormat);
+        OutputDebugStringW(Buffer);
+
+        Length -= BytesReturned;
+
+
+        if (MediaType.cbFormat)
+        {
+            MediaType.pbFormat = (BYTE*)CoTaskMemAlloc(MediaType.cbFormat);
+            if (!MediaType.pbFormat)
+                return E_OUTOFMEMORY;
+
+            hr = pStm->Read(&MediaType.pbFormat, sizeof(MediaType.cbFormat), &BytesReturned);
+            if (FAILED(hr))
+            {
+                swprintf(Buffer, L"ReadFormat failed with %lx\n", hr);
+                OutputDebugStringW(Buffer);
+                break;
+            }
+            Length -= BytesReturned;
+        }
+
+    }while(Length > 0);
+
+    DebugBreak();
+    return S_OK;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::Save(
+    IStream *pStm,
+    BOOL fClearDirty)
+{
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::Save Notimplemented\n");
+#endif
+
+    return E_NOTIMPL;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::GetSizeMax(
+    ULARGE_INTEGER *pcbSize)
+{
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::GetSizeMax Notimplemented\n");
+    DebugBreak();
+#endif
+
+    return E_NOTIMPL;
+}
+
+//-------------------------------------------------------------------
+// IAMDeviceRemoval interface
+//
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::DeviceInfo(CLSID *pclsidInterfaceClass, LPWSTR *pwszSymbolicLink)
+{
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::DeviceInfo\n");
+#endif
+
+    if (!m_DevicePath)
+    {
+        // object not initialized
+        return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND);
+    }
+
+    // copy device interface guid
+    CopyMemory(pclsidInterfaceClass, &m_DeviceInterfaceGUID, sizeof(GUID));
+
+    if (pwszSymbolicLink)
+    {
+        *pwszSymbolicLink = (LPWSTR)CoTaskMemAlloc((wcslen(m_DevicePath)+1) * sizeof(WCHAR));
+        if (!*pwszSymbolicLink)
+            return E_OUTOFMEMORY;
+
+        wcscpy(*pwszSymbolicLink, m_DevicePath);
+    }
+    return S_OK;
+}
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::Reassociate(void)
+{
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::Reassociate\n");
+#endif
+
+    if (!m_DevicePath || m_hDevice)
+    {
+        // file path not available
+        return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND);
+    }
+
+    m_hDevice = CreateFileW(m_DevicePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
+    if (!m_hDevice)
+    {
+        // failed to open device
+        return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
     }
 
-    WCHAR Buffer[MAX_PATH];
-    LPOLESTR lpstr;
-    StringFromCLSID(refiid, &lpstr);
-    swprintf(Buffer, L"CKsProxy::QueryInterface: NoInterface for %s !!!\n", lpstr);
-    OutputDebugStringW(Buffer);
-    CoTaskMemFree(lpstr);
+    // success
+    return NOERROR;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::Disassociate(void)
+{
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::Disassociate\n");
+#endif
 
+    if (!m_hDevice)
+        return E_HANDLE;
 
-    return E_NOINTERFACE;
+    CloseHandle(m_hDevice);
+    m_hDevice = NULL;
+    return NOERROR;
+}
+
+//-------------------------------------------------------------------
+// IKsClock interface
+//
+
+HANDLE
+STDMETHODCALLTYPE
+CKsProxy::KsGetClockHandle()
+{
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::KsGetClockHandle\n");
+#endif
+
+    return m_hClock;
 }
 
+
 //-------------------------------------------------------------------
 // IKsObject interface
 //
@@ -171,6 +2161,10 @@ HANDLE
 STDMETHODCALLTYPE
 CKsProxy::KsGetObjectHandle()
 {
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::KsGetObjectHandle\n");
+#endif
+
     return m_hDevice;
 }
 
@@ -181,6 +2175,10 @@ HRESULT
 STDMETHODCALLTYPE
 CKsProxy::InitNew( void)
 {
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::InitNew\n");
+#endif
+
     return S_OK;
 }
 
@@ -350,6 +2348,25 @@ CKsProxy::GetPinInstanceCount(
     return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_PIN), (PVOID)Instances, sizeof(KSPIN_CINSTANCES), &BytesReturned);
 }
 
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::GetPinCommunication(
+    ULONG PinId,
+    KSPIN_COMMUNICATION * Communication)
+{
+    KSP_PIN Property;
+    ULONG BytesReturned;
+
+    // setup request
+    Property.Property.Set = KSPROPSETID_Pin;
+    Property.Property.Id = KSPROPERTY_PIN_COMMUNICATION;
+    Property.Property.Flags = KSPROPERTY_TYPE_GET;
+    Property.PinId = PinId;
+    Property.Reserved = 0;
+
+    return KsSynchronousDeviceControl(m_hDevice, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSP_PIN), (PVOID)Communication, sizeof(KSPIN_COMMUNICATION), &BytesReturned);
+}
+
 HRESULT
 STDMETHODCALLTYPE
 CKsProxy::GetPinDataflow(
@@ -446,8 +2463,8 @@ CKsProxy::CreatePins()
     ULONG NumPins, Index;
     KSPIN_CINSTANCES Instances;
     KSPIN_DATAFLOW DataFlow;
+    KSPIN_COMMUNICATION Communication;
     HRESULT hr;
-    WCHAR Buffer[100];
     LPWSTR PinName;
     IPin * pPin;
     ULONG InputPin = 0;
@@ -465,6 +2482,11 @@ CKsProxy::CreatePins()
         if (FAILED(hr))
             continue;
 
+        // query pin communication;
+        hr = GetPinCommunication(Index, &Communication);
+        if (FAILED(hr))
+            continue;
+
         if (Instances.CurrentCount == Instances.PossibleCount)
         {
             // already maximum reached for this pin
@@ -487,7 +2509,7 @@ CKsProxy::CreatePins()
         // construct the pins
         if (DataFlow == KSPIN_DATAFLOW_IN)
         {
-            hr = CInputPin_Constructor((IBaseFilter*)this, PinName, m_hDevice, Index, IID_IPin, (void**)&pPin);
+            hr = CInputPin_Constructor((IBaseFilter*)this, PinName, m_hDevice, Index, Communication, IID_IPin, (void**)&pPin);
             if (FAILED(hr))
             {
                 CoTaskMemFree(PinName);
@@ -497,7 +2519,7 @@ CKsProxy::CreatePins()
         }
         else
         {
-            hr = COutputPin_Constructor((IBaseFilter*)this, PinName, IID_IPin, (void**)&pPin);
+            hr = COutputPin_Constructor((IBaseFilter*)this, PinName, Index, Communication, IID_IPin, (void**)&pPin);
             if (FAILED(hr))
             {
                 CoTaskMemFree(PinName);
@@ -509,8 +2531,12 @@ CKsProxy::CreatePins()
         // store pins
         m_Pins.push_back(pPin);
 
+#ifdef KSPROXY_TRACE
+        WCHAR Buffer[100];
         swprintf(Buffer, L"Index %lu DataFlow %lu Name %s\n", Index, DataFlow, PinName);
         OutputDebugStringW(Buffer);
+#endif
+
     }
 
     return S_OK;
@@ -521,10 +2547,16 @@ STDMETHODCALLTYPE
 CKsProxy::Load(IPropertyBag *pPropBag, IErrorLog *pErrorLog)
 {
     HRESULT hr;
-    WCHAR Buffer[100];
     VARIANT varName;
     LPGUID pGuid;
     ULONG NumGuids = 0;
+    HDEVINFO hList;
+    SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
+
+#ifdef KSPROXY_TRACE
+    WCHAR Buffer[100];
+    OutputDebugStringW(L"CKsProxy::Load\n");
+#endif
 
     // read device path
     varName.vt = VT_BSTR;
@@ -532,23 +2564,56 @@ CKsProxy::Load(IPropertyBag *pPropBag, IErrorLog *pErrorLog)
 
     if (FAILED(hr))
     {
+#ifdef KSPROXY_TRACE
         swprintf(Buffer, L"CKsProxy::Load Read %lx\n", hr);
         OutputDebugStringW(Buffer);
+#endif
+        return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
+    }
+
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"DevicePath: ");
+    OutputDebugStringW(varName.bstrVal);
+    OutputDebugStringW(L"\n");
+#endif
+
+    // create device list
+    hList = SetupDiCreateDeviceInfoListExW(NULL, NULL, NULL, NULL);
+    if (hList == INVALID_HANDLE_VALUE)
+    {
+        // failed to create device list
         return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
     }
 
+    DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
+    if (!SetupDiOpenDeviceInterfaceW(hList, (PCWSTR)varName.bstrVal, 0, &DeviceInterfaceData))
+    {
+        // failed to open device interface
+        SetupDiDestroyDeviceInfoList(hList);
+    }
+
+    // FIXME handle device interface links(aliases)
+    CopyMemory(&m_DeviceInterfaceGUID, &DeviceInterfaceData.InterfaceClassGuid, sizeof(GUID));
+
+    // close device info list
+   SetupDiDestroyDeviceInfoList(hList);
+
     // open device
     m_hDevice = CreateFileW(varName.bstrVal, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
 
     if (m_hDevice == INVALID_HANDLE_VALUE)
     {
         // failed to open device
+#ifdef KSPROXY_TRACE
         swprintf(Buffer, L"CKsProxy:: failed to open device with %lx\n", GetLastError());
         OutputDebugStringW(Buffer);
-
+#endif
         return MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
     }
 
+    // store device path
+    m_DevicePath = varName.bstrVal;
+
     // get all supported sets
     hr = GetSupportedSets(&pGuid, &NumGuids);
     if (FAILED(hr))
@@ -580,36 +2645,80 @@ HRESULT
 STDMETHODCALLTYPE
 CKsProxy::Save(IPropertyBag *pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties)
 {
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::Save\n");
+#endif
     return E_NOTIMPL;
 }
 
 //-------------------------------------------------------------------
 // IBaseFilter interface
-//
+//     
 
 HRESULT
 STDMETHODCALLTYPE
 CKsProxy::GetClassID(
     CLSID *pClassID)
 {
-    OutputDebugStringW(L"CKsProxy::GetClassID : NotImplemented\n");
-    return E_NOTIMPL;
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::GetClassID\n");
+#endif
+    CopyMemory(pClassID, &CLSID_Proxy, sizeof(GUID));
+
+    return S_OK;
 }
 
 HRESULT
 STDMETHODCALLTYPE
 CKsProxy::Stop()
 {
-    OutputDebugStringW(L"CKsProxy::Stop : NotImplemented\n");
-    return E_NOTIMPL;
+    HRESULT hr;
+
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::Stop\n");
+#endif
+
+    EnterCriticalSection(&m_Lock);
+
+    hr = SetPinState(KSSTATE_STOP);
+    if (SUCCEEDED(hr))
+        m_FilterState = State_Stopped;
+
+    LeaveCriticalSection(&m_Lock);
+
+    return hr;
 }
 
 HRESULT
 STDMETHODCALLTYPE
 CKsProxy::Pause()
 {
-    OutputDebugStringW(L"CKsProxy::Pause : NotImplemented\n");
-    return E_NOTIMPL;
+    HRESULT hr = S_OK;
+
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::Pause\n");
+#endif
+
+    EnterCriticalSection(&m_Lock);
+
+    if (m_FilterState == State_Running)
+    {
+        hr = SetPinState(KSSTATE_STOP);
+    }
+    if (SUCCEEDED(hr))
+    {
+        if (m_FilterState == State_Stopped)
+        {
+            hr = SetPinState(KSSTATE_PAUSE);
+        }
+    }
+
+    if (SUCCEEDED(hr))
+        m_FilterState = State_Paused;
+
+    LeaveCriticalSection(&m_Lock);
+    return hr;
+
 }
 
 HRESULT
@@ -617,8 +2726,110 @@ STDMETHODCALLTYPE
 CKsProxy::Run(
     REFERENCE_TIME tStart)
 {
-    OutputDebugStringW(L"CKsProxy::Run : NotImplemented\n");
-    return E_NOTIMPL;
+    HRESULT hr;
+
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::Run\n");
+#endif
+
+    EnterCriticalSection(&m_Lock);
+
+    if (m_FilterState == State_Stopped)
+    {
+        LeaveCriticalSection(&m_Lock);
+        // setting filter state to pause
+        hr = Pause();
+        if (FAILED(hr))
+            return hr;
+
+        EnterCriticalSection(&m_Lock);
+        assert(m_FilterState == State_Paused);
+    }
+
+    hr = SetPinState(KSSTATE_RUN);
+
+    if (SUCCEEDED(hr))
+    {
+        m_FilterState = State_Running;
+    }
+
+    LeaveCriticalSection(&m_Lock);
+    return hr;
+}
+
+HRESULT
+STDMETHODCALLTYPE
+CKsProxy::SetPinState(
+    KSSTATE State)
+{
+    HRESULT hr = S_OK;
+    ULONG Index;
+    IKsObject *pObject;
+    ULONG BytesReturned;
+    KSPROPERTY Property;
+    PIN_INFO PinInfo;
+
+    Property.Set = KSPROPSETID_Connection;
+    Property.Id = KSPROPERTY_CONNECTION_STATE;
+    Property.Flags = KSPROPERTY_TYPE_SET;
+
+    // set all pins to running state
+    for(Index = 0; Index < m_Pins.size(); Index++)
+    {
+        IPin * Pin = m_Pins[Index];
+        if (!Pin)
+            continue;
+
+        //check if the pin is connected
+        IPin * TempPin;
+        hr = Pin->ConnectedTo(&TempPin);
+        if (FAILED(hr))
+        {
+            // skip unconnected pins
+            continue;
+        }
+
+        // release connected pin
+        TempPin->Release();
+
+        // query for the pin info
+        hr = Pin->QueryPinInfo(&PinInfo);
+
+        if (SUCCEEDED(hr))
+        {
+            if (PinInfo.pFilter)
+                PinInfo.pFilter->Release();
+
+            if (PinInfo.dir == PINDIR_OUTPUT)
+            {
+                hr = COutputPin_SetState(Pin, State);
+                if (SUCCEEDED(hr))
+                    continue;
+            }
+        }
+
+        //query IKsObject interface
+        hr = Pin->QueryInterface(IID_IKsObject, (void**)&pObject);
+
+        // get pin handle
+        HANDLE hPin = pObject->KsGetObjectHandle();
+
+        // sanity check
+        assert(hPin && hPin != INVALID_HANDLE_VALUE);
+
+        // now set state
+        hr = KsSynchronousDeviceControl(hPin, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&State, sizeof(KSSTATE), &BytesReturned);
+
+#ifdef KSPROXY_TRACE
+        WCHAR Buffer[100];
+        swprintf(Buffer, L"CKsProxy::SetPinState Index %u State %u hr %lx\n", Index, State, hr);
+        OutputDebugStringW(Buffer);
+#endif
+
+        if (FAILED(hr))
+            return hr;
+    }
+    return hr;
 }
 
 HRESULT
@@ -627,6 +2838,9 @@ CKsProxy::GetState(
     DWORD dwMilliSecsTimeout,
     FILTER_STATE *State)
 {
+    if (!State)
+        return E_POINTER;
+
     *State = m_FilterState;
     return S_OK;
 }
@@ -636,6 +2850,101 @@ STDMETHODCALLTYPE
 CKsProxy::SetSyncSource(
     IReferenceClock *pClock)
 {
+    HRESULT hr;
+    IKsClock *pKsClock;
+    HANDLE hClock, hPin;
+    ULONG Index;
+    IPin * pin;
+    IKsObject * pObject;
+    KSPROPERTY Property;
+    ULONG BytesReturned;
+    PIN_DIRECTION PinDir;
+
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::SetSyncSource\n");
+#endif
+
+    // FIXME
+    // need locks
+
+    if (pClock)
+    {
+        hr = pClock->QueryInterface(IID_IKsClock, (void**)&pKsClock);
+        if (FAILED(hr))
+        {
+            hr = m_ReferenceClock->QueryInterface(IID_IKsClock, (void**)&pKsClock);
+            if (FAILED(hr))
+                return hr;
+        }
+
+        // get clock handle
+        hClock = pKsClock->KsGetClockHandle();
+
+        // release IKsClock interface
+        pKsClock->Release();
+        m_hClock = hClock;
+    }
+    else
+    {
+        // no clock handle
+        m_hClock = NULL;
+    }
+
+
+    // distribute clock to all pins
+    for(Index = 0; Index < m_Pins.size(); Index++)
+    {
+        // get current pin
+        pin = m_Pins[Index];
+        if (!pin)
+            continue;
+
+        // get IKsObject interface
+        hr = pin->QueryInterface(IID_IKsObject, (void **)&pObject);
+        if (SUCCEEDED(hr))
+        {
+            // get pin handle
+            hPin = pObject->KsGetObjectHandle();
+            if (hPin != INVALID_HANDLE_VALUE && hPin)
+            {
+                // set clock
+                Property.Set = KSPROPSETID_Stream;
+                Property.Id = KSPROPERTY_STREAM_MASTERCLOCK;
+                Property.Flags = KSPROPERTY_TYPE_SET;
+
+                // set master clock
+                hr = KsSynchronousDeviceControl(hPin, IOCTL_KS_PROPERTY, (PVOID)&Property, sizeof(KSPROPERTY), (PVOID)&m_hClock, sizeof(HANDLE), &BytesReturned);
+
+                if (FAILED(hr))
+                {
+                    if (hr != MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_SET_NOT_FOUND) &&
+                        hr != MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_NOT_FOUND))
+                    {
+                        // failed to set master clock
+                        pObject->Release();
+                        WCHAR Buffer[100];
+                        swprintf(Buffer, L"CKsProxy::SetSyncSource KSPROPERTY_STREAM_MASTERCLOCK failed with %lx\n", hr);
+                        OutputDebugStringW(Buffer);
+                        return hr;
+                    }
+                }
+            }
+            // release IKsObject
+            pObject->Release();
+        }
+
+        // now get the direction
+        hr = pin->QueryDirection(&PinDir);
+        if (SUCCEEDED(hr))
+        {
+            if (PinDir == PINDIR_OUTPUT)
+            {
+                // notify pin via
+                //CBaseStreamControl::SetSyncSource(pClock)
+            }
+        }
+    }
+
     if (pClock)
     {
         pClock->AddRef();
@@ -647,6 +2956,9 @@ CKsProxy::SetSyncSource(
     }
 
     m_ReferenceClock = pClock;
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::SetSyncSource done\n");
+#endif
     return S_OK;
 }
 
@@ -655,6 +2967,10 @@ STDMETHODCALLTYPE
 CKsProxy::GetSyncSource(
     IReferenceClock **pClock)
 {
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::GetSyncSource\n");
+#endif
+
     if (!pClock)
         return E_POINTER;
 
@@ -670,6 +2986,10 @@ STDMETHODCALLTYPE
 CKsProxy::EnumPins(
     IEnumPins **ppEnum)
 {
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::EnumPins\n");
+#endif
+
     return CEnumPins_fnConstructor(m_Pins, IID_IEnumPins, (void**)ppEnum);
 }
 
@@ -680,6 +3000,10 @@ CKsProxy::FindPin(
 {
     ULONG PinId;
 
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::FindPin\n");
+#endif
+
     if (!ppPin)
         return E_POINTER;
 
@@ -714,9 +3038,16 @@ CKsProxy::QueryFilterInfo(
     if (!pInfo)
         return E_POINTER;
 
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::QueryFilterInfo\n");
+#endif
+
     pInfo->achName[0] = L'\0';
     pInfo->pGraph = m_pGraph;
 
+    if (m_pGraph)
+        m_pGraph->AddRef();
+
     return S_OK;
 }
 
@@ -726,6 +3057,12 @@ CKsProxy::JoinFilterGraph(
     IFilterGraph *pGraph,
     LPCWSTR pName)
 {
+#ifdef KSPROXY_TRACE
+    WCHAR Buffer[100];
+    swprintf(Buffer, L"CKsProxy::JoinFilterGraph pName %s pGraph %p m_Ref %u\n", pName, pGraph, m_Ref);
+    OutputDebugStringW(Buffer);
+#endif
+
     if (pGraph)
     {
         // joining filter graph
@@ -746,8 +3083,10 @@ STDMETHODCALLTYPE
 CKsProxy::QueryVendorInfo(
     LPWSTR *pVendorInfo)
 {
-    OutputDebugStringW(L"CKsProxy::QueryVendorInfo : NotImplemented\n");
-    return E_NOTIMPL;
+#ifdef KSPROXY_TRACE
+    OutputDebugStringW(L"CKsProxy::QueryVendorInfo\n");
+#endif
+    return StringFromCLSID(CLSID_Proxy, pVendorInfo);
 }
 
 //-------------------------------------------------------------------
@@ -758,7 +3097,10 @@ HRESULT
 STDMETHODCALLTYPE
 CKsProxy::Register()
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"CKsProxy::Register : NotImplemented\n");
+#endif
+
     return E_NOTIMPL;
 }
 
@@ -766,7 +3108,9 @@ HRESULT
 STDMETHODCALLTYPE
 CKsProxy::Unregister()
 {
+#ifdef KSPROXY_TRACE
     OutputDebugStringW(L"CKsProxy::Unregister : NotImplemented\n");
+#endif
     return E_NOTIMPL;
 }
 
@@ -777,11 +3121,13 @@ CKsProxy_Constructor(
     REFIID riid,
     LPVOID * ppv)
 {
+#ifdef KSPROXY_TRACE
     WCHAR Buffer[100];
     LPOLESTR pstr;
     StringFromCLSID(riid, &pstr);
     swprintf(Buffer, L"CKsProxy_Constructor pUnkOuter %p riid %s\n", pUnkOuter, pstr);
     OutputDebugStringW(Buffer);
+#endif
 
     CKsProxy * handler = new CKsProxy();