code:
//**@@@*@@@****************************************************
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//**@@@*@@@****************************************************

//
// FileName:    audfilter.cpp
//
// Abstract:
//      This is the implementation file for C++ classes that expose
//      functionality of KS filters that support streaming of PCM Audio
//

#include "kssample.h"

// ============================================================================
//
//   CKsAudFilter
//
//=============================================================================

////////////////////////////////////////////////////////////////////////////////
//
//  CKsAudFilter::CKsAudFilter()
//
//  Routine Description:
//      CKsAudFilter constructor
//
//  Arguments:
//      xxxx
//
//
//  Return Value:
//
//     S_OK on success
//

CKsAudFilter::CKsAudFilter
(
    LPCTSTR  pszName,
    HRESULT  *phr
) : CKsFilter(pszName, phr)
{
    TRACE_ENTER();
    TRACE_LEAVE_HRESULT(*phr);
    return;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsAudFilter::EnumeratePins()
//
//  Routine Description:
//      EnumeratePins
//
//  Arguments:
//      xxxx
//
//
//  Return Value:
//
//     S_OK on success
//     E_FAIL on failure
//

HRESULT CKsAudFilter::EnumeratePins(void)
{
    TRACE_ENTER();
    HRESULT hr = S_OK;
    ULONG   cPins = 0;
    BOOL    fOutOfMemory = FALSE;
    KSPIN_COMMUNICATION ksPinCommunication = KSPIN_COMMUNICATION_NONE;
    KSPIN_DATAFLOW ksPinDataflow = (KSPIN_DATAFLOW)0;

    // get the number of pins supported by SAD
    hr =
        GetPinPropertySimple
        (
            0,
            KSPROPSETID_Pin,
            KSPROPERTY_PIN_CTYPES,
            &cPins,
            sizeof(cPins)
        );

    if (FAILED(hr))
    {
        DebugPrintf(TRACE_ERROR, TEXT("Failed to retrieve count of pins in audio filter"));
    }
    else // (SUCCEEDED(hr))
    {
        //
        // loop through the pins, looking for audio pins
        //
        for(ULONG nPinId = 0; nPinId < cPins; nPinId++)
        {

            // This information is needed to create the right type of pin

            //
            // get COMMUNICATION ---------------
            //
            ksPinCommunication = KSPIN_COMMUNICATION_NONE;
            hr =
                GetPinPropertySimple
                (
                    nPinId,
                    KSPROPSETID_Pin,
                    KSPROPERTY_PIN_COMMUNICATION,
                    &ksPinCommunication,
                    sizeof(KSPIN_COMMUNICATION)
                );
            if (FAILED(hr))
            {
                DebugPrintf(TRACE_ERROR, TEXT("Failed to retrieve pin property KSPROPERTY_PIN_COMMUNICATION"));
            }

            if (SUCCEEDED(hr))
            {
                // ILL communication
                if ( (ksPinCommunication != KSPIN_COMMUNICATION_SOURCE) &&
                    (ksPinCommunication != KSPIN_COMMUNICATION_SINK) &&
                    (ksPinCommunication != KSPIN_COMMUNICATION_BOTH) )
                {
                    DebugPrintf(TRACE_ERROR, TEXT("Pin communication value doesn't make sense"));
                    hr = E_FAIL;
                }
            }

            ksPinDataflow = (KSPIN_DATAFLOW)0;
            if (SUCCEEDED(hr))
            {
                //
                // Get the data flow property
                //
                hr =
                    GetPinPropertySimple
                    (
                        nPinId,
                        KSPROPSETID_Pin,
                        KSPROPERTY_PIN_DATAFLOW,
                        &ksPinDataflow,
                        sizeof(KSPIN_DATAFLOW)
                    );
                if (FAILED(hr))
                {
                    DebugPrintf(TRACE_ERROR, TEXT("Failed to retrieve pin property KSPROPERTY_PIN_DATAFLOW"));
                }
            }

            //
            // create a new pin
            //
            CKsAudPin* pNewPin = NULL;

            if (SUCCEEDED(hr))
            {
                // If the pin is an IRP sink and inputs data, it's a render pin
                if ((KSPIN_COMMUNICATION_SINK == ksPinCommunication)
                &&  (KSPIN_DATAFLOW_IN == ksPinDataflow))
                {
                    pNewPin = new CKsAudRenPin(this, nPinId, &hr);
                }
                // If the pin is an IRP sink and outputs data, it's a capture pin
                else if ((KSPIN_COMMUNICATION_SINK == ksPinCommunication)
                     &&  (KSPIN_DATAFLOW_OUT == ksPinDataflow))
                {
                    pNewPin = new CKsAudCapPin(this, nPinId, &hr);
                }
                // Otherwise, it's just a pin
                else
                {
                    pNewPin = new CKsAudPin(this, nPinId, &hr);
                }

                if (NULL == pNewPin)
                {
                    DebugPrintf(TRACE_ERROR, TEXT("Failed to create audio pin"));
                    hr = E_OUTOFMEMORY;
                    fOutOfMemory = TRUE;
                    break;
                }
            }

            if (SUCCEEDED(hr))
            {
                if (NULL == m_listPins.AddTail(pNewPin))
                {
                    delete pNewPin;
                    DebugPrintf(TRACE_ERROR, TEXT("Unable to allocate list entry to save pin in"));
                    fOutOfMemory = TRUE;
                    hr = E_OUTOFMEMORY;
                    break;
                }
            }
            else //if (FAILED(hr))
            {
                delete pNewPin;
            }
        }
    }

    // If we ran out of memory, delete all the pins, as we're in a bad state
    if (fOutOfMemory)
    {
        DebugPrintf(TRACE_ERROR, TEXT("Ran out of memory enumerating pins - deleting all pins"));

        CKsPin* pPin;
        while (m_listPins.RemoveHead( &pPin ))
        {
            delete pPin;
        }

        hr = E_OUTOFMEMORY;
    }
    else
    {
        ClassifyPins();

        if( m_listRenderSinkPins.IsEmpty()
        &&  m_listRenderSourcePins.IsEmpty()
        &&  m_listCaptureSinkPins.IsEmpty()
        &&  m_listCaptureSourcePins.IsEmpty() )
        {
            DebugPrintf(TRACE_ERROR, TEXT("No valid pins found on the filter"));
            hr = E_FAIL;
        }
        else
        {
            hr = S_OK;
        }
    }

    TRACE_LEAVE_HRESULT(hr);
    return hr;
}

// ============================================================================
//
//   CKsAudRenFilter
//
//=============================================================================

////////////////////////////////////////////////////////////////////////////////
//
//  CKsAudRenFilter::CKsAudRenFilter()
//
//  Routine Description:
//      CKsAudRenFilter constructor
//
//  Arguments:
//      xxxx
//
//
//  Return Value:
//
//     S_OK on success
//
CKsAudRenFilter::CKsAudRenFilter
(
    LPCTSTR  pszName,
    HRESULT  *phr
) : CKsAudFilter(pszName, phr)
{
    TRACE_ENTER();

    m_eType = eAudRen;

    TRACE_LEAVE_HRESULT(*phr);
    return;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsAudRenFilter::FindViablePin()
//
//  Routine Description:
//      Look through the given list and find one that can do pwfx
//
//  Arguments:
//      WAVEFORMATEX that the pin must support
//
//
//  Return Value:
//
//     S_OK on success
//
CKsAudRenPin*
CKsAudRenFilter::FindViablePin
(
    const WAVEFORMATEX*   pwfx
)
{
    TRACE_ENTER();
    assert( pwfx );

    CKsPin*  pNode;
    LISTPOS listPos = m_listRenderSinkPins.GetHeadPosition();
    while(m_listRenderSinkPins.GetNext( listPos, &pNode ))
    {
        CKsAudRenPin* pPin = (CKsAudRenPin*)pNode;

        // To only look at non-digital output pins, check that pPin->IsVolumeSupported() is TRUE,
        // as digital output pins don't have volume controls associated with them.
        if( pPin->IsFormatSupported( pwfx ) )
        {
            // This should be a valid pin
            TRACE_LEAVE();
            return pPin;
        }
    }

    TRACE_LEAVE();
    return NULL;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsAudRenFilter::CreateRenderPin()
//
//  Routine Description:
//      Look through m_listRenderPins and find one that can do pwfx and create it
//
//  Arguments:
//      WAVEFORMATEX that the pin must support
//      Flag whether or not the pin plays backed looped buffers or streamed buffers
//
//  Return Value:
//
//     S_OK on success
//
CKsAudRenPin*
CKsAudRenFilter::CreateRenderPin
(
    const WAVEFORMATEX*   pwfx,
    BOOL            fLooped
)
{
    TRACE_ENTER();
    HRESULT hr = S_OK;

    CKsAudRenPin* pPin = FindViablePin(pwfx);

    if (!pPin)
    {
        DebugPrintf(TRACE_NORMAL, TEXT("Could not find a Render pin that supports the given wave format"));
        hr = E_FAIL;
    }
    else
    {
        hr = pPin->SetFormat(pwfx);

        if (FAILED(hr))
        {
            DebugPrintf(TRACE_ERROR, TEXT("Failed to set Render Pin format - the pin lied about its supported formats"));
        }
    }

    if (SUCCEEDED(hr))
    {
        hr = pPin->Instantiate(fLooped);

        if (SUCCEEDED(hr))
        {
            DebugPrintf(TRACE_LOW, TEXT("Successfully instantiated Render Pin.  Handle = 0x%08x"), pPin->GetHandle());
        }
        else
        {
            DebugPrintf(TRACE_ERROR, TEXT("Failed to instantiate Render Pin"));
        }
    }

    if (FAILED(hr))
    {
        // Initialize pPin to NULL again
        pPin = NULL;

        // Try to intstantiate all the pins, one at a time
        CKsPin *pKsPin;
        LISTPOS listPosPin = m_listRenderSinkPins.GetHeadPosition();
        while( !pPin && m_listRenderSinkPins.GetNext( listPosPin, &pKsPin ))
        {
            CKsAudRenPin *pKsAudRenPin = (CKsAudRenPin *)pKsPin;
            hr = pKsAudRenPin->SetFormat( pwfx );
            if (SUCCEEDED(hr))
            {
                hr = pKsAudRenPin->Instantiate(fLooped);
            }

            if (SUCCEEDED(hr))
            {
                // Save the pin in pPin
                pPin = pKsAudRenPin;
                break;
            }
        }
    }

    if (FAILED(hr))
    {
        // Don't delete the pin - it's still in m_listRenderPins
        //delete pPin;
        pPin = NULL;
    }
    else
    {
        // Remove the pin from the filter's list of pins
        LISTPOS listPosPinNode = m_listPins.Find( pPin );
        assert(listPosPinNode);
        m_listPins.RemoveAt( listPosPinNode );

        listPosPinNode = m_listRenderSinkPins.Find( pPin );
        assert(listPosPinNode);
        m_listRenderSinkPins.RemoveAt( listPosPinNode );
    }

    TRACE_LEAVE_HRESULT(hr);
    return pPin;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsAudRenFilter::CanCreateRenderPin()
//
//  Routine Description:
//      Look through m_listRenderPins and check if one that supports the given wave format
//
//  Arguments:
//      WAVEFORMATEX that the pin must support
//
//
//  Return Value:
//
//     TRUE if there is a pin that supports the format, FALSE otherwise
//
BOOL
CKsAudRenFilter::CanCreateRenderPin
(
    const WAVEFORMATEX*   pwfx
)
{
    TRACE_ENTER();
    HRESULT hr = S_OK;

    CKsAudRenPin* pPin = FindViablePin(pwfx);

    if (!pPin)
    {
        DebugPrintf(TRACE_NORMAL, TEXT("Could not find a Render pin that supports the given wave format"));
        hr = E_FAIL;
    }

    TRACE_LEAVE_HRESULT(hr);
    return SUCCEEDED(hr);
}

// ============================================================================
//
//   CKsAudCapFilter
//
//=============================================================================

////////////////////////////////////////////////////////////////////////////////
//
//  CKsAudCapFilter::CKsAudCapFilter()
//
//  Routine Description:
//      CKsAudCapFilter constructor
//
//  Arguments:
//      xxxx
//
//
//  Return Value:
//
//     S_OK on success
//

CKsAudCapFilter::CKsAudCapFilter
(
    LPCTSTR  pszName,
    HRESULT  *phr
) : CKsAudFilter(pszName, phr)
{
    TRACE_ENTER();

    m_eType = eAudCap;

    TRACE_LEAVE_HRESULT(*phr);
    return;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsAudCapFilter::FindViablePin()
//
//  Routine Description:
//      Look through the given list and find one that can do pwfx
//
//  Arguments:
//      xxxx
//
//
//  Return Value:
//
//     S_OK on success
//

CKsAudCapPin*
CKsAudCapFilter::FindViablePin
(
    WAVEFORMATEX*   pwfx
)
{
    TRACE_ENTER();
    assert( pwfx );

    CKsPin*  pNode;
    LISTPOS listPos = m_listCaptureSinkPins.GetHeadPosition();
    while(m_listCaptureSinkPins.GetNext( listPos, &pNode ))
    {
        CKsAudCapPin* pPin = (CKsAudCapPin*)pNode;

        if( pPin->IsFormatSupported( pwfx ) )
        {
            // This should be a valid pin
            TRACE_LEAVE();
            return pPin;
        }
    }

    TRACE_LEAVE();
    return NULL;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsAudCapFilter::CreateCapturePin()
//
//  Routine Description:
//      Look through m_listCapturePins and find one that can do pwfx and create it
//
//  Arguments:
//      xxxx
//
//
//  Return Value:
//
//     S_OK on success
//

CKsAudCapPin*
CKsAudCapFilter::CreateCapturePin
(
    WAVEFORMATEX*   pwfx,
    BOOL            fLooped
)
{
    TRACE_ENTER();
    HRESULT hr = S_OK;

    CKsAudCapPin*   pPin = FindViablePin(pwfx);

    if (!pPin)
    {
        DebugPrintf(TRACE_ERROR, TEXT("Could not find a Capture pin that supports the given wave format"));
        hr = E_FAIL;
    }
    else
    {
        hr = pPin->SetFormat(pwfx);

        if (FAILED(hr))
        {
            DebugPrintf(TRACE_ERROR, TEXT("Failed to set Capture Pin format"));
        }
    }

    if (SUCCEEDED(hr))
    {
        hr = pPin->Instantiate(fLooped);

        if (SUCCEEDED(hr))
        {
            DebugPrintf(TRACE_LOW, TEXT("Successfully instantiated Capture Pin.  Handle = 0x%08x"), pPin->GetHandle());
        }
        else
        {
            DebugPrintf(TRACE_ERROR, TEXT("Failed to instantiate Capture Pin"));
        }
    }

    if (FAILED(hr))
    {
        delete pPin;
        pPin = NULL;
    }

    TRACE_LEAVE_HRESULT(hr);
    return pPin;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsAudCapFilter::GetCapturePin()
//
//  Routine Description:
//      Returns the Capture Pin
//
//  Arguments:
//      ppPin -- A pointer to a pointer to a CKsAudCapPin
//
//
//  Return Value:
//
//     S_OK on success
//

HRESULT CKsAudCapFilter::GetCapturePin(CKsAudCapPin** ppPin)
{
    TRACE_ENTER();
    HRESULT hr = S_OK;
    CKsPin* pPin = NULL;

    if (NULL == ppPin)
    {
        hr = E_POINTER;
    }

    if (SUCCEEDED(hr))
    {
        // Get the first pin on the list
        if (!m_listPins.GetHead(&pPin))
        {
            hr = E_FAIL;
        }
    }

    if (SUCCEEDED(hr))
    {
        *ppPin = static_cast<CKsAudCapPin*>(pPin);
    }

    TRACE_LEAVE_HRESULT(hr);
    return hr;
}


code:
//**@@@*@@@****************************************************
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//**@@@*@@@****************************************************

//
// FileName:    audfilter.h
//
// Abstract:
//      This is the header file for C++ classes that expose
//      functionality of KS filters that support PCM audio formats
//

#pragma once
#ifndef __KSAUDFILTER_H
#define __KSAUDFILTER_H

// Forward Declarations
class CKsAudPin;
class CKsAudRenPin;
class CKsAudCapPin;

////////////////////////////////////////////////////////////////////////////////
//
//  class CKsAudFilter
//
//  Class Description:
//      This is the base class for a Audio Render Filter.
//
//
//

class CKsAudFilter : public CKsFilter
{
public:
    virtual HRESULT EnumeratePins(void);

protected:
    CKsAudFilter
    (
        LPCTSTR  pszName,
        HRESULT  *phr
    );
};

////////////////////////////////////////////////////////////////////////////////
//
//  class CKsAudRenFilter
//
//  Class Description:
//      This is the base class for a Audio Render Filter.
//
//
//

class CKsAudRenFilter : public CKsAudFilter
{
public:
    CKsAudRenFilter
    (
        LPCTSTR  pszName,
        HRESULT  *phr
    );

    CKsAudRenPin* CreateRenderPin(const WAVEFORMATEX* pwfx, BOOL fLooped);
    BOOL            CanCreateRenderPin(const WAVEFORMATEX* pwfx);
private:
    CKsAudRenPin* FindViablePin(const WAVEFORMATEX* pwfx);
};

////////////////////////////////////////////////////////////////////////////////
//
//  class CKsAudCapFilter
//
//  Class Description:
//      This is the base class for an Audio Capture Filter.
//
//
//

class CKsAudCapFilter : public CKsAudFilter
{
public:
    CKsAudCapFilter
    (
        LPCTSTR  pszName,
        HRESULT* phr
    );

    HRESULT GetCapturePin(CKsAudCapPin** ppPin);

    CKsAudCapPin* CreateCapturePin(WAVEFORMATEX* pwfx, BOOL fLooped);

private:
    CKsAudCapPin* FindViablePin(WAVEFORMATEX* pwfx);
};

#endif //__KSAUDFILTER_H

repo_name: ninjam/libninjam

license: mit


code:
//**@@@*@@@****************************************************
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//**@@@*@@@****************************************************

//
// FileName:    audpin.cpp
//
// Abstract:
//      This is the implementation file for C++ classes that expose
//      functionality of KS pins that support streaming of PCM Audio
//

#include "kssample.h"

// ============================================================================
//
//   CKsAudPin
//
//=============================================================================

// Utitlity Function

inline BOOL
IsEqualGUIDAligned(GUID guid1, GUID guid2)
{
    return ((*(PLONGLONG)(&guid1) == *(PLONGLONG)(&guid2)) && (*((PLONGLONG)(&guid1) + 1) == *((PLONGLONG)(&guid2) + 1)));
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsAudPin::CKsAudPin()
//
//  Routine Description:
//      CKsAudPin
//
//  Arguments:
//      Parent filter
//      Pin ID
//      Result of creation
//
//
//  Return Value:
//
//     S_OK on success
//

CKsAudPin::CKsAudPin
(
    CKsAudFilter*  pFilter,
    ULONG       nId,
    HRESULT* phr
) : CKsPin(pFilter, nId, phr),
    m_pAudFilter(pFilter),
    m_pWaveFormatEx(NULL),
    m_pksDataFormatWfx(NULL)
{
    TRACE_ENTER();
    HRESULT hr = *phr;

    if (SUCCEEDED(hr))
    {
        hr = m_listDataRange.Initialize(1);
        if (FAILED(hr))
            DebugPrintf(TRACE_ERROR,TEXT("Failed to Initialize m_listDataRange"));
    }

    if (SUCCEEDED(hr))
    {
        hr = m_listNodes.Initialize(1);
        if (FAILED(hr))
            DebugPrintf(TRACE_ERROR,TEXT("Failed to Initialize m_listNodes"));
    }

    // create a KSPIN_CONNECT structure to describe a waveformatex pin
    if (SUCCEEDED(hr))
    {
        m_cbPinCreateSize = sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX);
        m_pksPinCreate = (PKSPIN_CONNECT)new BYTE[m_cbPinCreateSize];
        if (!m_pksPinCreate)
        {
            DebugPrintf(TRACE_ERROR,TEXT("Failed to allocate m_pksPinCreate"));
            hr = E_OUTOFMEMORY;
        }
    }

    if (SUCCEEDED(hr))
    {
        m_pksPinCreate->Interface.Set              = KSINTERFACESETID_Standard;
        m_pksPinCreate->Interface.Id               = KSINTERFACE_STANDARD_STREAMING;
        m_pksPinCreate->Interface.Flags            = 0;
        m_pksPinCreate->Medium.Set                 = KSMEDIUMSETID_Standard;
        m_pksPinCreate->Medium.Id                  = KSMEDIUM_TYPE_ANYINSTANCE;
        m_pksPinCreate->Medium.Flags               = 0;
        m_pksPinCreate->PinId                      = nId;
        m_pksPinCreate->PinToHandle                = NULL;
        m_pksPinCreate->Priority.PriorityClass     = KSPRIORITY_NORMAL;
        m_pksPinCreate->Priority.PrioritySubClass  = 1;

        // point m_pksDataFormatWfx to just after the pConnect struct
        PKSDATAFORMAT_WAVEFORMATEX pksDataFormatWfx = (PKSDATAFORMAT_WAVEFORMATEX)(m_pksPinCreate + 1);

        // set up format for KSDATAFORMAT_WAVEFORMATEX
        pksDataFormatWfx->DataFormat.FormatSize = sizeof(KSDATAFORMAT_WAVEFORMATEX);
        pksDataFormatWfx->DataFormat.Flags = 0;
        pksDataFormatWfx->DataFormat.Reserved = 0;
        pksDataFormatWfx->DataFormat.MajorFormat = KSDATAFORMAT_TYPE_AUDIO;
        pksDataFormatWfx->DataFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
        pksDataFormatWfx->DataFormat.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX;

        m_pksDataFormatWfx = pksDataFormatWfx;
    }

    // Initialize the Pin;
    if (SUCCEEDED(hr))
    {
        hr = CKsAudPin::Init();
    }

    TRACE_LEAVE_HRESULT(hr);
    *phr = hr;
    return;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsAudPin::~CKsAudPin()
//
//  Routine Description:
//      xxxx
//
//  Arguments:
//      xxxx
//
//
//  Return Value:
//
//     none
//

CKsAudPin::~CKsAudPin(void)
{
    TRACE_ENTER();
    KSDATARANGE_AUDIO *pKSDATARANGE_AUDIO;
    CKsNode *pKsNode;

    // Clear datarange list
    while( m_listDataRange.RemoveHead(&pKSDATARANGE_AUDIO) )
    {
        delete pKSDATARANGE_AUDIO;
    }

    // Clear the node list
    while( m_listNodes.RemoveHead(&pKsNode) )
    {
        delete pKsNode;
    }

    delete[] (BYTE *)m_pWaveFormatEx;

    TRACE_LEAVE();
    return;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsAudPin::Init()
//
//  Routine Description:
//      Initialize internal data structures and does some sanity-checking
//
//  Arguments:
//      None
//
//  Return Value:
//
//     S_OK on success
//

HRESULT CKsAudPin::Init()
{
    TRACE_ENTER();
    HRESULT hr = S_OK;
    BOOL fViablePin = FALSE;

    // Make sure at least one interface is standard streaming
    if (SUCCEEDED(hr))
    {
        fViablePin = FALSE;
        for(ULONG i = 0; i < m_Descriptor.cInterfaces && !fViablePin; i++)
        {
            fViablePin =
                fViablePin ||
                IsEqualGUIDAligned(m_Descriptor.pInterfaces[i].Set, KSINTERFACESETID_Standard) &&
                (m_Descriptor.pInterfaces[i].Id == KSINTERFACE_STANDARD_STREAMING) ;
        }

        if (!fViablePin)
        {
            DebugPrintf(TRACE_ERROR, TEXT("No standard streaming interfaces on the pin"));
            hr = E_FAIL;
        }
    }

    // Make sure at least one medium is standard streaming
    if (SUCCEEDED(hr))
    {
        fViablePin = FALSE;
        for(ULONG i = 0; i < m_Descriptor.cInterfaces && !fViablePin; i++)
        {
            fViablePin =
                fViablePin ||
                IsEqualGUIDAligned(m_Descriptor.pMediums[i].Set, KSMEDIUMSETID_Standard) &&
                (m_Descriptor.pMediums[i].Id == KSMEDIUM_STANDARD_DEVIO) ;
        }

        if (!fViablePin)
        {
            DebugPrintf(TRACE_ERROR, TEXT("No standard streaming mediums on the pin"));
            hr = E_FAIL;
        }
    }

    // Make sure at least one datarange supports audio
    if (SUCCEEDED(hr))
    {
        fViablePin = FALSE;
        PKSDATARANGE pDataRange = m_Descriptor.pDataRanges;

        for(ULONG i = 0; i < m_Descriptor.cDataRanges; i++)
        {
            // SubType should either be compatible with WAVEFORMATEX or
            // it should be WILDCARD
            fViablePin =
                fViablePin ||
                IS_VALID_WAVEFORMATEX_GUID(&pDataRange->SubFormat) ||
                IsEqualGUIDAligned(pDataRange->SubFormat, KSDATAFORMAT_SUBTYPE_PCM) ||
                IsEqualGUIDAligned(pDataRange->SubFormat, KSDATAFORMAT_SUBTYPE_WILDCARD);

            if (fViablePin && IsEqualGUIDAligned(pDataRange->MajorFormat, KSDATAFORMAT_TYPE_AUDIO))
            {
                // Copy the data range into the pin
                PKSDATARANGE_AUDIO pCopyDataRangeAudio = new KSDATARANGE_AUDIO;
                if( pCopyDataRangeAudio )
                {
                    PKSDATARANGE_AUDIO pDataRangeAudio = (PKSDATARANGE_AUDIO)pDataRange;
                    CopyMemory( pCopyDataRangeAudio, pDataRangeAudio, sizeof(KSDATARANGE_AUDIO) );
                    if (NULL == m_listDataRange.AddTail( pCopyDataRangeAudio ))
                    {
                        delete pCopyDataRangeAudio;
                        pCopyDataRangeAudio = NULL;
                        DebugPrintf(TRACE_ERROR, TEXT("Unable to allocate list entry to save datarange in"));
                        hr = E_OUTOFMEMORY;
                    }
                }
                else
                {
                    DebugPrintf(TRACE_ERROR, TEXT("Unable to allocate memory to save datarange in"));
                    hr = E_OUTOFMEMORY;
                }
            }

            pDataRange = (PKSDATARANGE)( ((PBYTE)pDataRange) + pDataRange->FormatSize);
        }

        if (!fViablePin)
        {
            DebugPrintf(TRACE_ERROR, TEXT("No audio dataranges on the pin"));
            hr = E_FAIL;
        }
    }

    TRACE_LEAVE_HRESULT(hr);
    return hr;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsAudPin::SetFormat()
//
//  Routine Description:
//      Sets the format
//
//  Arguments:
//      Format to use when creating pin
//
//
//  Return Value:
//
//     S_OK on success
//

HRESULT
CKsAudPin::SetFormat
(
    const WAVEFORMATEX* pwfx
)
{
    TRACE_ENTER();
    HRESULT hr = S_OK;

    if (!(pwfx && m_pksDataFormatWfx))
    {
        DebugPrintf(TRACE_ERROR,TEXT("pwfx or m_pksDataFormatWfx are NULL"));
        hr = E_FAIL;
    }

    DWORD dwNewFormatSize = 0;
    if (SUCCEEDED(hr))
    {
        dwNewFormatSize = GetWfxSize(pwfx);

        // If the new format differs in size from the old format, re-allocate m_pksPinCreate
        if( m_cbPinCreateSize !=
            dwNewFormatSize + sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX) - sizeof(WAVEFORMATEX) )
        {
            // create a KSPIN_CONNECT structure to describe a waveformatex pin
            DWORD dwNewSize = dwNewFormatSize + sizeof(KSPIN_CONNECT) + sizeof(KSDATAFORMAT_WAVEFORMATEX) - sizeof(WAVEFORMATEX);
            void *pPinCreate = new BYTE[dwNewSize];
            if (!pPinCreate)
            {
                DebugPrintf(TRACE_ERROR,TEXT("Unable to allocate KSPIN_CONNECT structure"));
                hr = E_OUTOFMEMORY;
            }
            else
            {
                // Copy the old pin structure to the new one
                CopyMemory( pPinCreate, m_pksPinCreate, min(dwNewSize, m_cbPinCreateSize) );

                // Free the old structure
                delete[] m_pksPinCreate;
                m_pksPinCreate = NULL;

                // point m_pksPinCreate at the new structure
                m_pksPinCreate = (PKSPIN_CONNECT)pPinCreate;

                // point m_pksDataFormatWfx to just after the pConnect struct
                m_pksDataFormatWfx = (PKSDATAFORMAT_WAVEFORMATEX)(m_pksPinCreate + 1);

                // Set the new format size parameter
                m_pksDataFormatWfx->DataFormat.FormatSize = dwNewFormatSize + sizeof(KSDATAFORMAT_WAVEFORMATEX) - sizeof(WAVEFORMATEX);
            }
        }
    }

    if (SUCCEEDED(hr))
    {
        // Copy the new format into pksDataFormatWfx
        PKSDATAFORMAT_WAVEFORMATEX pksDataFormatWfx = m_pksDataFormatWfx;
        CopyMemory(&pksDataFormatWfx->WaveFormatEx, pwfx, dwNewFormatSize);

        // Set the sample size in pksDataFormatWfx
        pksDataFormatWfx->DataFormat.SampleSize = (USHORT)(pwfx->nChannels * pwfx->wBitsPerSample / 8);

        // Save the wave format
        delete[] (BYTE*)m_pWaveFormatEx;
        m_pWaveFormatEx = (WAVEFORMATEX *)new BYTE[dwNewFormatSize];
        if( m_pWaveFormatEx )
        {
            CopyMemory(m_pWaveFormatEx, pwfx, dwNewFormatSize);
        }
    }

    TRACE_LEAVE_HRESULT(hr);
    return hr;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsAudPin::GetPosition()
//
//  Routine Description:
//      Gets the current position
//
//  Arguments:
//      Address to store the position
//
//
//  Return Value:
//
//     S_OK on success
//

HRESULT
CKsAudPin::GetPosition
(
    KSAUDIO_POSITION* pPos
)
{
    TRACE_ENTER();
    HRESULT hr = S_OK;

    if (NULL == pPos)
    {
        hr = E_INVALIDARG;
    }

    if (SUCCEEDED(hr))
    {
        hr = GetPropertySimple(KSPROPSETID_Audio, KSPROPERTY_AUDIO_POSITION, pPos, sizeof(KSAUDIO_POSITION));

        if (FAILED(hr))
        {
            DebugPrintf(TRACE_ERROR, TEXT("Failed to retrieve audio stream position - %#08x"), hr);
        }
    }

    TRACE_LEAVE_HRESULT(hr);
    return hr;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsAudPin::SetPosition()
//
//  Routine Description:
//      Sets the current position
//
//  Arguments:
//      Address of new position
//
//
//  Return Value:
//
//     S_OK on success
//

HRESULT
CKsAudPin::SetPosition
(
    KSAUDIO_POSITION* pPos
)
{
    TRACE_ENTER();
    HRESULT hr = S_OK;

    if (NULL == pPos)
    {
        hr = E_INVALIDARG;
    }

    if (SUCCEEDED(hr))
    {
        hr = SetPropertySimple(KSPROPSETID_Audio, KSPROPERTY_AUDIO_POSITION, pPos, sizeof(KSAUDIO_POSITION));

        if (FAILED(hr))
        {
            DebugPrintf(TRACE_ERROR, TEXT("Failed to set audio stream position - %#08x"), hr);
        }
    }

    TRACE_LEAVE_HRESULT(hr);
    return hr;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsAudPin::GetNode()
//
//  Routine Description:
//
//      Get the CKsNode* in m_listNodes for a given ID value
//
//  Arguments:
//
//      Node ID
//
//  Return Value:
//
//      Pointer to the matching CKsNode, if any
//

CKsNode* CKsAudPin::GetNode(ULONG ulNodeID)
{
    TRACE_ENTER();
    CKsNode *pksNode = NULL;
    LISTPOS listPos = m_listNodes.GetHeadPosition();
    while( m_listNodes.GetNext( listPos, &pksNode ) )
    {
        if( ulNodeID == pksNode->GetId())
        {
            break;
        }
    }

    TRACE_LEAVE();
    return pksNode;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsAudPin::IsFormatSupported()
//
//  Routine Description:
//      Check if the given format is supported
//
//  Arguments:
//      Waveformat to check against
//
//
//  Return Value:
//
//     TRUE if format is supported
//

BOOL CKsAudPin::IsFormatSupported(const WAVEFORMATEX* pwfx)
{
    TRACE_ENTER();

    LISTPOS             listPosRange = m_listDataRange.GetHeadPosition();
    KSDATARANGE_AUDIO*  pKSDATARANGE_AUDIO;

    while( m_listDataRange.GetNext( listPosRange, &pKSDATARANGE_AUDIO )  )
    {
        if( KSDATAFORMAT_TYPE_WILDCARD == pKSDATARANGE_AUDIO->DataRange.MajorFormat
        ||  KSDATAFORMAT_TYPE_AUDIO == pKSDATARANGE_AUDIO->DataRange.MajorFormat )
        {
            // Set the format to search for
            GUID guidFormat = {DEFINE_WAVEFORMATEX_GUID(pwfx->wFormatTag)};

            // If this is a WaveFormatExtensible structure, then use its defined SubFormat
            if( WAVE_FORMAT_EXTENSIBLE == pwfx->wFormatTag )
            {
                guidFormat = ((WAVEFORMATEXTENSIBLE *)pwfx)->SubFormat;
            }

            if( KSDATAFORMAT_SUBTYPE_WILDCARD == pKSDATARANGE_AUDIO->DataRange.SubFormat
            ||  guidFormat == pKSDATARANGE_AUDIO->DataRange.SubFormat )
            {
                if( KSDATAFORMAT_SPECIFIER_WILDCARD == pKSDATARANGE_AUDIO->DataRange.Specifier
                ||  KSDATAFORMAT_SPECIFIER_WAVEFORMATEX == pKSDATARANGE_AUDIO->DataRange.Specifier )
                {
                    if( pKSDATARANGE_AUDIO->MaximumChannels >= pwfx->nChannels
                    &&  pKSDATARANGE_AUDIO->MinimumBitsPerSample <= pwfx->wBitsPerSample
                    &&  pKSDATARANGE_AUDIO->MaximumBitsPerSample >= pwfx->wBitsPerSample
                    &&  pKSDATARANGE_AUDIO->MinimumSampleFrequency <= pwfx->nSamplesPerSec
                    &&  pKSDATARANGE_AUDIO->MaximumSampleFrequency >= pwfx->nSamplesPerSec )
                    {
                        // This should be a valid pin
                        TRACE_LEAVE();
                        return TRUE;
                    }
                }
            }
        }
    }

    TRACE_LEAVE();
    return FALSE;
}

// ============================================================================
//
//   CKsAudRenPin
//
//=============================================================================

////////////////////////////////////////////////////////////////////////////////
//
//  CKsAudRenPin::CKsAudRenPin()
//
//  Routine Description:
//      CKsAudRenPin
//
//  Arguments:
//      Parent filter
//      Pin ID
//      Result of creation
//
//  Return Value:
//
//     None
//
CKsAudRenPin::CKsAudRenPin
(
    CKsAudFilter*  pFilter,
    ULONG       nId,
    HRESULT* phr
) : CKsAudPin(pFilter, nId, phr)
{
    TRACE_ENTER();
    m_eType = eAudRen;

    TRACE_LEAVE_HRESULT(*phr);
    return;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsAudRenPin::~CKsAudRenPin()
//
//  Routine Description:
//      xxxx
//
//  Arguments:
//      xxxx
//
//
//  Return Value:
//
//     none
//
CKsAudRenPin::~CKsAudRenPin(void)
{
    TRACE_ENTER();

    TRACE_LEAVE();
    return;
}

// ============================================================================
//
//   CKsAudCapPin
//
//=============================================================================

////////////////////////////////////////////////////////////////////////////////
//
//  CKsAudCapPin::CKsAudCapPin()
//
//  Routine Description:
//      CKsAudCapPin
//
//  Arguments:
//      Parent filter
//      Pin ID
//      Result of creation
//
//  Return Value:
//
//     S_OK on success
//

CKsAudCapPin::CKsAudCapPin
(
    CKsAudFilter*  pFilter,
    ULONG       nId,
    HRESULT* phr
) : CKsAudPin(pFilter, nId, phr)
{
    TRACE_ENTER();
    m_eType = eAudCap;

    TRACE_LEAVE_HRESULT(*phr);
    return;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsAudCapPin::~CKsAudCapPin()
//
//  Routine Description:
//      xxxx
//
//  Arguments:
//      xxxx
//
//
//  Return Value:
//
//     none
//

CKsAudCapPin::~CKsAudCapPin(void)
{
    TRACE_ENTER();
    TRACE_LEAVE();
    return;
}


code:
//**@@@*@@@****************************************************
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//**@@@*@@@****************************************************

//
// FileName:    audpin.h
//
// Abstract:
//      This is the header file for C++ classes that expose
//      functionality of KS pins that support PCM audio formats
//

#pragma once
#ifndef __KSAUDPIN_H
#define __KSAUDPIN_H

#include <ksmedia.h>

#ifndef _MSC_VER
typedef struct {
    KSDATAFORMAT    DataFormat;
    WAVEFORMATEX    WaveFormatEx;
} KSDATAFORMAT_WAVEFORMATEX, *PKSDATAFORMAT_WAVEFORMATEX;
#endif

#ifndef _WAVEFORMATEXTENSIBLE_
#define _WAVEFORMATEXTENSIBLE_
typedef struct {
    WAVEFORMATEX    Format;
    union {
        WORD wValidBitsPerSample;       /* bits of precision  */
        WORD wSamplesPerBlock;          /* valid if wBitsPerSample==0 */
        WORD wReserved;                 /* If neither applies, set to zero. */
    } Samples;
    DWORD           dwChannelMask;      /* which channels are */
                                        /* present in stream  */
    GUID            SubFormat;
} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
#endif // !_WAVEFORMATEXTENSIBLE_

#if !defined(WAVE_FORMAT_EXTENSIBLE)
#define  WAVE_FORMAT_EXTENSIBLE                 0xFFFE
#endif // !defined(WAVE_FORMAT_EXTENSIBLE)

// Forward Declarations
class CKsNode;
class CKsAudFilter;

////////////////////////////////////////////////////////////////////////////////
//
//  class CKsAudPin
//
//  Class Description:
//      This is the base class for an Audio pin.
//
//
//

class CKsAudPin : public CKsPin
{
public:
    // Data Members
    TList<KSDATARANGE_AUDIO> m_listDataRange;

public:
    // constructor
    CKsAudPin(CKsAudFilter* pFilter, ULONG nId, HRESULT *phr);

    // destructor
    virtual ~CKsAudPin(void);

    // Various other methods
    HRESULT SetFormat(const WAVEFORMATEX* pwfx);
    const WAVEFORMATEX* GetFormat(void) {return m_pWaveFormatEx;}

    HRESULT GetPosition(KSAUDIO_POSITION* Pos);
    HRESULT SetPosition(KSAUDIO_POSITION* Pos);

    BOOL    IsFormatSupported(const WAVEFORMATEX* pwfx);

protected:
    CKsAudFilter*   m_pAudFilter;

private:
    HRESULT         Init(void);
    CKsNode*        GetNode(ULONG ulNodeID);

    TList<CKsNode>              m_listNodes;

    WAVEFORMATEX*               m_pWaveFormatEx;
    KSDATAFORMAT_WAVEFORMATEX*  m_pksDataFormatWfx; // Just a reference into m_pksPinCreate
};

////////////////////////////////////////////////////////////////////////////////
//
//  class CKsAudRenPin
//
//  Class Description:
//      This is the base class for a Audio Render pin.
//
//
//

class CKsAudRenPin : public CKsAudPin
{
public:
    // constructor
    CKsAudRenPin(CKsAudFilter* pFilter, ULONG nId, HRESULT *phr);

    // destructor
    virtual ~CKsAudRenPin(void);

};

////////////////////////////////////////////////////////////////////////////////
//
//  class CKsAudCapPin
//
//  Class Description:
//      This is the base class for an Audio Capture pin.
//
//
//

class CKsAudCapPin : public CKsAudPin
{
public:
    // constructor
    CKsAudCapPin(CKsAudFilter* pFilter, ULONG nId, HRESULT *phr);

    // destructor
    virtual ~CKsAudCapPin(void);
};

#endif //__KSAUDPIN_H


code:
//**@@@*@@@****************************************************
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//**@@@*@@@****************************************************

//
// FileName:    enum.cpp
//
// Abstract:
//      This is the implementation file for the C++ class which encapsulates
//      the setupDi functions needed to enumerate KS Filters
//

#include "kssample.h"
#include <setupapi.h>
#include <mmsystem.h>

// ============================================================================
//
//   CKsEnumFilters
//
//=============================================================================

// Utility Function

inline BOOL
IsEqualGUIDAligned(GUID guid1, GUID guid2)
{
    return ((*(PLONGLONG)(&guid1) == *(PLONGLONG)(&guid2)) && (*((PLONGLONG)(&guid1) + 1) == *((PLONGLONG)(&guid2) + 1)));
}

///////////////////////////////////////////////////////////////////////////////
//
//  CKsEnumFilters::CKsEnumFilters()
//
//  Routine Description:
//      Constructor
//
//  Arguments:
//      HRESULT* phr -- The results of the construction.  Because the lists
//      allocate memory we have to be able to fail construction.  The results
//      are propigated back to the caller through this argument.  If
//      construction fails the state of the object is undefined
//
//
//  Return Value:
//      None, but there is a side-effect parameter
//

CKsEnumFilters::CKsEnumFilters(HRESULT* phr)
{
    TRACE_ENTER();
    HRESULT hr;

    // Initialize the list
    hr = m_listFilters.Initialize(1);

    TRACE_LEAVE_HRESULT(hr);
    *phr = hr;
    return;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsEnumFilters::~CKsEnumFilters()
//
//  Routine Description:
//      CKsFilter Destructor
//
//  Arguments:
//      None
//
//  Return Value:
//      None
//

CKsEnumFilters::~CKsEnumFilters()
{
    TRACE_ENTER();
    HRESULT hr = S_OK;

    hr = DestroyLists();

    assert(SUCCEEDED(hr));

    TRACE_LEAVE_HRESULT(hr);
    return;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsEnumFilters::DestroyLists()
//
//  Routine Description:
//      Dumps the contents of the lists
//
//  Arguments:
//      None
//
//
//  Return Value:
//
//     S_OK on success
//

HRESULT CKsEnumFilters::DestroyLists()
{
    TRACE_ENTER();
    HRESULT hr = S_OK;

    CKsFilter* pFilter;

    // clean list of filters
    while(m_listFilters.RemoveHead(&pFilter))
    {
        delete pFilter;
    }

    TRACE_LEAVE_HRESULT(hr);
    return hr;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsEnumFilters::EnumFilters()
//
//  Routine Description:
//      Enumerate filters that match the given parameters
//
//  Arguments:
//      Filter attributes
//
//
//  Return Value:
//
//     S_OK on success
//

HRESULT CKsEnumFilters::EnumFilters(
    IN  ETechnology eFilterType,
    IN  GUID*   aguidCategories,
    IN  ULONG   cguidCategories,
    IN  BOOL    fNeedPins,          // = TRUE // Enumerates devices for sysaudio.
    IN  BOOL    fNeedNodes,         // = TRUE
    IN  BOOL    fInstantiate)       // = TRUE // Should we instantiate.
{
    TRACE_ENTER();

    HRESULT hr = DestroyLists();
    HDEVINFO hDevInfo = NULL;

    if (SUCCEEDED(hr)
    &&  aguidCategories
    &&  !IsEqualGUIDAligned(GUID_NULL, aguidCategories[0]))
    {
        // Get a handle to the device set specified by the guid
        hDevInfo =
            SetupDiGetClassDevs
            (
                &(aguidCategories[0]),
                NULL,
                NULL,
                DIGCF_PRESENT | DIGCF_DEVICEINTERFACE
            );

        if( !CKsIrpTarget::IsValidHandle(hDevInfo) )
        {
            hr = E_FAIL;
            DebugPrintf(TRACE_NORMAL, TEXT("No devices found"));
        }
        else
        {
            // Loop through members of the set and get details for each
            for(int iClassMember = 0;;iClassMember++)
            {
                DWORD                               cbInterfaceDetails;
                SP_DEVICE_INTERFACE_DATA            DID;
                SP_DEVICE_INTERFACE_DATA            DIDAlias;
                SP_DEVINFO_DATA                     DevInfoData;
                SP_DEVICE_INTERFACE_DETAIL_DATA*    pDevInterfaceDetails;

                DID.cbSize = sizeof(DID);
                DID.Reserved = 0;
                DIDAlias.cbSize = sizeof(DIDAlias);
                DIDAlias.Reserved = 0;

                DevInfoData.cbSize = sizeof(DevInfoData);
                DevInfoData.Reserved = 0;

                BOOL fRes =
                    SetupDiEnumDeviceInterfaces
                    (
                        hDevInfo,
                        NULL,
                        &(aguidCategories[0]),
                        iClassMember,
                        &DID
                    );

                if (!fRes)
                {
                    // This just means that we've enumerate all the devices - it's not a real error
                    break;
                }

                // Get details for the device registered in this class
                cbInterfaceDetails = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + MAX_PATH * sizeof(WCHAR);
                pDevInterfaceDetails = (SP_DEVICE_INTERFACE_DETAIL_DATA*)new BYTE[cbInterfaceDetails];
                if (!pDevInterfaceDetails)
                {
                    hr = E_OUTOFMEMORY;
                    DebugPrintf(TRACE_NORMAL, TEXT("Failed to allocate SP_DEVICE_INTERFACE_DETAIL_DATA structure"));
                    break;
                }

                pDevInterfaceDetails->cbSize = sizeof(*pDevInterfaceDetails);

                fRes =
                    SetupDiGetDeviceInterfaceDetail
                    (
                        hDevInfo,
                        &DID,
                        pDevInterfaceDetails,
                        cbInterfaceDetails,
                        NULL,
                        &DevInfoData
                    );

                if (fRes)
                {
                    //
                    // check additional category guids which may (or may not) have been supplied
                    //
                    for(ULONG nguidCategory = 1; nguidCategory < cguidCategories && fRes; nguidCategory++)
                    {
                        fRes =
                            SetupDiGetDeviceInterfaceAlias
                            (
                                hDevInfo,
                                &DID,
                                &(aguidCategories[nguidCategory]),
                                &DIDAlias
                            );

                        if (!fRes)
                        {
                            DebugPrintf(TRACE_LOW, TEXT("Failed to get requested DeviceInterfaceAlias"));
                        }

                        //
                        // Check if the this interface alias is enabled.
                        //
                        if (fRes)
                        {
                            if (!DIDAlias.Flags || (DIDAlias.Flags & SPINT_REMOVED))
                            {
                                fRes = FALSE;
                                DebugPrintf(TRACE_LOW, TEXT("DeviceInterfaceAlias disabled."));
                            }
                        }
                    }

                    if (fRes)
                    {
                        CKsFilter* pnewFilter = NULL;
                        HRESULT hrFilter = S_OK;

                        switch(eFilterType)
                        {
                            case eUnknown:
                                pnewFilter = new CKsFilter(pDevInterfaceDetails->DevicePath,&hrFilter);
                                break;

                            case eAudRen:
                                pnewFilter = new CKsAudRenFilter(pDevInterfaceDetails->DevicePath, &hrFilter);
                                break;

                            case eAudCap:
                                pnewFilter = new CKsAudCapFilter(pDevInterfaceDetails->DevicePath, &hrFilter);
                                break;

                            default:
                                pnewFilter = new CKsFilter(pDevInterfaceDetails->DevicePath,  &hrFilter);
                                break;
                        }

                        if (NULL == pnewFilter)
                        {
                            hrFilter = E_OUTOFMEMORY;
                        }
                        else
                        {
                            if (SUCCEEDED(hrFilter) && (fNeedNodes || fNeedPins || fInstantiate))
                            {
                                hrFilter = pnewFilter->Instantiate();

                                if (fNeedNodes && SUCCEEDED(hrFilter))
                                    hrFilter = pnewFilter->EnumerateNodes();

                                // This enumerates Devices for SysAudio devices
                                // For normal devices, it just enumerates the pins
                                if (fNeedPins && SUCCEEDED(hrFilter))
                                    hrFilter = pnewFilter->EnumeratePins();
                            }

                            if (SUCCEEDED(hrFilter))
                            {
                                if (NULL == m_listFilters.AddTail(pnewFilter))
                                {
                                    hrFilter = E_OUTOFMEMORY;
                                }
                            }
                        }

                        if (FAILED(hrFilter))
                        {
                            delete pnewFilter;
                            DebugPrintf(
                                TRACE_ERROR,
                                TEXT("Failed to create filter for %s"),
                                pDevInterfaceDetails->DevicePath);
                        }
                    }
                }

                delete[] (BYTE*)pDevInterfaceDetails;
            } // for
        }
    }

    if (CKsIrpTarget::IsValidHandle(hDevInfo))
        SetupDiDestroyDeviceInfoList(hDevInfo);

    // If we didn't find anything, be sure to return an error code
    if (SUCCEEDED(hr)
    &&  m_listFilters.IsEmpty())
    {
        hr = E_FAIL;
    }

    TRACE_LEAVE_HRESULT(hr);
    return hr;
}


code:
//**@@@*@@@****************************************************
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//**@@@*@@@****************************************************

//
// FileName:    enum.h
//
// Abstract:
//      This is the header file for the C++ class which encapsulates
//      the setupDi functions needed to enumerate KS Filters
//

#pragma once
#ifndef __KSENUM_H
#define __KSENUM_H

// Forward Declarations
class CKsFilter;
struct _SP_DEVICE_INTERFACE_DATA;
struct _SP_DEVINFO_DATA;

////////////////////////////////////////////////////////////////////////////////
//
//  class CKsEnumFilters
//
//  Class Description:
//      This is a utility class used for enumerating KS filters.
//      Basic usage is
//          instantiate a CKsEnumFilters
//          call EnumFilters, which enumerates a list of filters
//          pick a filter to use from m_listFilters
//          either call RemoveFilterFromList to remove the filter from the list,
//          or duplicate the filter and use the duplicate copy.
//
//
//

class CKsEnumFilters
{
public:
    // This is the list of the filters
    TList<CKsFilter> m_listFilters;

public:
    CKsEnumFilters(
        OUT HRESULT* phr);

    virtual ~CKsEnumFilters(void);

    virtual HRESULT DestroyLists(void);

    HRESULT EnumFilters(
        IN  ETechnology eFilterType,
        IN  GUID*   aguidCategories,
        IN  ULONG   cguidCategories,
        IN  BOOL    fNeedPins,          // = TRUE // Enumerates devices for sysaudio.
        IN  BOOL    fNeedNodes,         // = TRUE
        IN  BOOL    fInstantiate);      // = TRUE // Should we instantiate.

    HRESULT RemoveFilterFromList(
        IN  CKsFilter* pKsFilter);
};

#endif //__KSENUM_H


code:
//**@@@*@@@****************************************************
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//**@@@*@@@****************************************************

//
// FileName:    filter.cpp
//
// Abstract:
//      This is the implementation file for C++ classes that expose
//      functionality of KS filter objects
//

#include "kssample.h"
#include <winioctl.h>

// ============================================================================
//
//   CKsFilter
//
//=============================================================================

////////////////////////////////////////////////////////////////////////////////
//
//  CKsFilter::InternalInit()
//
//  Routine Description:
//      Internal Initialization Function.  It zero's out the strings and calls
//      initialzie on all of the lists.
//
//  Arguments:
//      None
//
//  Return Value:
//
//     S_OK on success.  Propigates all failures.
//

HRESULT CKsFilter::InternalInit()
{
    TRACE_ENTER();
    HRESULT hr = S_OK;

    // Zero out the strings
    ZeroMemory(m_szFilterName, sizeof m_szFilterName);

    // Initialize the Lists
    hr = m_listCaptureSinkPins.Initialize(1);
    if SUCCEEDED(hr)
    {
        hr = m_listCaptureSourcePins.Initialize(1);
        if (FAILED(hr))
            DebugPrintf(TRACE_ERROR,TEXT("Failed to Initialize m_listCaptureSourcePins"));
    }

    if (SUCCEEDED(hr))
    {
        hr = m_listNoCommPins.Initialize(1);
        if (FAILED(hr))
            DebugPrintf(TRACE_ERROR,TEXT("Failed to Initialize m_listNoCommPins"));
    }

    if (SUCCEEDED(hr))
    {
        hr = m_listPins.Initialize(1);
        if (FAILED(hr))
            DebugPrintf(TRACE_ERROR,TEXT("Failed to Initialize m_listPins"));
    }

    if (SUCCEEDED(hr))
    {
        hr = m_listRenderSinkPins.Initialize(1);
        if (FAILED(hr))
            DebugPrintf(TRACE_ERROR,TEXT("Failed to Initialize m_listRenderSinkPins"));
    }

    if (SUCCEEDED(hr))
    {
        hr = m_listRenderSourcePins.Initialize(1);
        if (FAILED(hr))
            DebugPrintf(TRACE_ERROR,TEXT("Failed to Initialize m_listRenderSourcePins"));
    }

    if (SUCCEEDED(hr))
    {
        hr = m_listNodes.Initialize(1);
        if (FAILED(hr))
            DebugPrintf(TRACE_ERROR,TEXT("Failed to Initialize m_listNodes"));
    }

    TRACE_LEAVE_HRESULT(hr);
    return hr;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsFilter::CKsFilter()
//
//  Routine Description:
//      Constructor
//
//  Arguments:
//      Strings and more Strings!
//
//
//  Return Value:
//
//     S_OK on success
//

CKsFilter::CKsFilter (
    LPCTSTR     pszName,
    HRESULT*   phr)
    : CKsIrpTarget(INVALID_HANDLE_VALUE),
    m_eType(eUnknown)
{
    TRACE_ENTER();
    HRESULT hr = S_OK;

    hr = InternalInit();

    if (NULL == pszName)
    {
        hr = E_INVALIDARG;
        DebugPrintf(TRACE_ERROR,TEXT("pszName cannot be NULL"));
    }

    if (SUCCEEDED(hr))
    {
        _tcsncpy(m_szFilterName, pszName, MAX_PATH);
    }

    TRACE_LEAVE_HRESULT(hr);
    *phr = hr;
    return;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsFilter::DestroyLists()
//
//  Routine Description:
//      Dumps the contents of the lists
//
//  Arguments:
//      None
//
//
//  Return Value:
//
//     S_OK on success
//

HRESULT CKsFilter::DestroyLists()
{
    TRACE_ENTER();
    HRESULT hr = S_OK;

    CKsPin* pPin;
    CKsNode *pKsNode;

    // Clear the node list
    while( m_listNodes.RemoveHead(&pKsNode) )
    {
        delete pKsNode;
    }

    // clean pins
    while(m_listPins.RemoveHead(&pPin))
    {
        delete pPin;
    }

    // empty shallow copy lists
    while (m_listRenderSinkPins.RemoveHead(&pPin));
    while(m_listRenderSourcePins.RemoveHead(&pPin));
    while(m_listCaptureSinkPins.RemoveHead(&pPin));
    while(m_listCaptureSourcePins.RemoveHead(&pPin));
    while(m_listNoCommPins.RemoveHead(&pPin));

    TRACE_LEAVE_HRESULT(hr);
    return hr;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsFilter::~CKsFilter()
//
//  Routine Description:
//      CKsFilter Destructor
//
//  Arguments:
//      None
//
//  Return Value:
//      None
//

CKsFilter::~CKsFilter()
{
    TRACE_ENTER();
    HRESULT hr = S_OK;

    hr = DestroyLists();
    SafeCloseHandle(m_handle);

    assert(SUCCEEDED(hr));

    TRACE_LEAVE_HRESULT(hr);
    return;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsFilter::Instantiate()
//
//  Routine Description:
//      Instantiates the pin
//
//  Arguments:
//      None, Make sure that the object is fully initialized before calling this function
//
//
//  Return Value:
//
//     S_OK on success
//

HRESULT CKsFilter::Instantiate(void)
{
    TRACE_ENTER();
    HRESULT hr = S_OK;

    m_handle = CreateFile(
        m_szFilterName,
        GENERIC_READ | GENERIC_WRITE,
        0,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
        NULL);

    if (!IsValidHandle(m_handle))
    {
        hr = E_FAIL;
    }

    if (FAILED(hr))
    {
        DWORD dwError = GetLastError();
        DebugPrintf(TRACE_ERROR,TEXT("CKsFilter::Instantiate: CreateFile failed for device %s.  ErrorCode = 0x%08x"),m_szFilterName, dwError);
    }

    TRACE_LEAVE_HRESULT(hr);
    return hr;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsFilter::EnumeratePins()
//
//  Routine Description:
//      Enumerates Pins
//
//  Arguments:
//      None
//
//
//  Return Value:
//
//     S_OK on success
//

HRESULT CKsFilter::EnumeratePins(void)
{
    TRACE_ENTER();
    HRESULT hr = S_OK;
    HRESULT   hrWarn        = S_OK;
    DWORD   fViableFilter   = FALSE;
    HANDLE  hPin            = NULL;
    ULONG   cPins, nPinId;
    DWORD   dwKsRet         = ERROR_NOT_SUPPORTED;

    hr = GetPinPropertySimple(
        0,
        KSPROPSETID_Pin,
        KSPROPERTY_PIN_CTYPES,
        &cPins,
        sizeof cPins );

    if (SUCCEEDED(hr))
    {
        // Loop through the pins
        for (nPinId = 0; nPinId < cPins; nPinId++)
        {
            // create a new CKsPin
            hr = S_OK;
            CKsPin* pNewPin = new CKsPin(this,nPinId, &hr);

            if (FAILED(hr))
            {
                DebugPrintf(TRACE_ERROR, TEXT("Failed to construct pin"));
                goto break_loop;
            }
            else if (NULL == pNewPin)
            {
                hr = E_OUTOFMEMORY;
                DebugPrintf(TRACE_ERROR, TEXT("Failed to create pin"));
                goto break_loop;
            }

            if (NULL==m_listPins.AddTail(pNewPin))
            {
                DebugPrintf(TRACE_ERROR, TEXT("Failed to add pin to list"));
                goto break_loop;
            }
            continue;

       break_loop:

            delete pNewPin;
            pNewPin = NULL;
        }
    }

    hr = ClassifyPins();

    fViableFilter = (
        m_listCaptureSinkPins.GetCount()    ||
        m_listCaptureSourcePins.GetCount()  ||
        m_listRenderSinkPins.GetCount()     ||
        m_listRenderSourcePins.GetCount()   ||
        m_listNoCommPins.GetCount() );

    if (!fViableFilter)
    {
        hr = E_FAIL;
        DebugPrintf(TRACE_ERROR, TEXT("Filter is not viable. It has no pins."));
    }

    TRACE_LEAVE_HRESULT(hr);
    return hr;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsFilter::ClassifyPins()
//
//  Routine Description:
//      Classify Pins
//
//  Arguments:
//      None -- It operates on the internal m_listPins
//
//  Return Value:
//
//     S_OK on success
//

HRESULT CKsFilter::ClassifyPins()
{
    TRACE_ENTER();
    HRESULT hr = S_OK;
    LISTPOS pos;
    CKsPin* pPin = NULL;
    KSPIN_COMMUNICATION Communication;
    KSPIN_DATAFLOW DataFlow;

    pos = m_listPins.GetHeadPosition();

    while(SUCCEEDED(hr) && m_listPins.GetNext(pos, &pPin))
    {
        hr = pPin->GetCommunication(&Communication);
        if (FAILED(hr))
        {
            break;
        }

        hr = pPin->GetDataFlow(&DataFlow);
        if (FAILED(hr))
        {
            break;
        }

        if (KSPIN_DATAFLOW_IN == DataFlow)
        {
            switch(Communication)
            {
                case KSPIN_COMMUNICATION_SINK:
                    if (NULL == m_listRenderSinkPins.AddTail(pPin))
                    {
                        hr = E_OUTOFMEMORY;
                    }
                    break;

                case KSPIN_COMMUNICATION_SOURCE:
                    if (NULL == m_listCaptureSourcePins.AddTail(pPin))
                    {
                        hr = E_OUTOFMEMORY;
                    }
                    break;

                case KSPIN_COMMUNICATION_BOTH:
                    if (NULL == m_listRenderSinkPins.AddTail(pPin))
                    {
                        hr = E_OUTOFMEMORY;
                    }
                    if (NULL == m_listCaptureSourcePins.AddTail(pPin))
                    {
                        hr = E_OUTOFMEMORY;
                    }
                    break;

                case KSPIN_COMMUNICATION_NONE:
                    if (NULL == m_listNoCommPins.AddTail(pPin))
                    {
                        hr = E_OUTOFMEMORY;
                    }
                    break;

                default:
                    DebugPrintf(TRACE_LOW,TEXT("Pin communication type not recognized"));
                    break;
            }
        }
        else
        {
            switch(Communication)
            {
                case KSPIN_COMMUNICATION_SINK:
                    if (NULL == m_listCaptureSinkPins.AddTail(pPin))
                    {
                        hr = E_OUTOFMEMORY;
                    }
                    break;

                case KSPIN_COMMUNICATION_SOURCE:
                    if (NULL == m_listRenderSourcePins.AddTail(pPin))
                    {
                        hr = E_OUTOFMEMORY;
                    }
                    break;

                case KSPIN_COMMUNICATION_BOTH:
                    if (NULL == m_listCaptureSinkPins.AddTail(pPin))
                    {
                        hr = E_OUTOFMEMORY;
                    }
                    if (NULL == m_listRenderSourcePins.AddTail(pPin))
                    {
                        hr = E_OUTOFMEMORY;
                    }
                    break;

                case KSPIN_COMMUNICATION_NONE:
                    if (NULL == m_listNoCommPins.AddTail(pPin))
                    {
                        hr = E_OUTOFMEMORY;
                    }
                    break;

                default:
                    DebugPrintf(TRACE_LOW,TEXT("Pin communication type not recognized"));
                    break;
            }
        }
    }

    TRACE_LEAVE_HRESULT(hr);
    return hr;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsFilter::GetPinPropertySimple()
//
//  Routine Description:
//      Gets simple pin properties
//
//  Arguments:
//      Pin property stuff
//
//
//  Return Value:
//
//     S_OK on success
//

HRESULT CKsFilter::GetPinPropertySimple(
    IN  ULONG   nPinId,
    IN  REFGUID guidPropertySet,
    IN  ULONG   nProperty,
    OUT PVOID   pvValue,
    OUT ULONG   cbValue)
{
    TRACE_ENTER();
    HRESULT hr = S_OK;

    ULONG ulReturned = 0;
    KSP_PIN ksPProp;

    ksPProp.Property.Set = guidPropertySet;
    ksPProp.Property.Id = nProperty;
    ksPProp.Property.Flags = KSPROPERTY_TYPE_GET;
    ksPProp.PinId = nPinId;
    ksPProp.Reserved = 0;

    hr = SyncIoctl(
        m_handle,
        IOCTL_KS_PROPERTY,
        &ksPProp,
        sizeof(KSP_PIN),
        pvValue,
        cbValue,
        &ulReturned);

    TRACE_LEAVE_HRESULT(hr);
    return hr;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsFilter::GetPinPropertyMulti()
//
//  Routine Description:
//      Gets multiple pin properties
//
//  Arguments:
//      Pin property stuff
//
//
//  Return Value:
//
//     S_OK on success
//

HRESULT CKsFilter::GetPinPropertyMulti(
    IN  ULONG               nPinId,
    IN  REFGUID             guidPropertySet,
    IN  ULONG               nProperty,
    OUT PKSMULTIPLE_ITEM*   ppKsMultipleItem)
{
    TRACE_ENTER();
    HRESULT hr = S_OK;
    ULONG   ulReturned = 0;
    ULONG   cbMultipleItem = 0;
    KSP_PIN ksPProp;

    ksPProp.Property.Set = guidPropertySet;
    ksPProp.Property.Id = nProperty;
    ksPProp.Property.Flags = KSPROPERTY_TYPE_GET;
    ksPProp.PinId = nPinId;
    ksPProp.Reserved = 0;

    hr = SyncIoctl(
        m_handle,
        IOCTL_KS_PROPERTY,
        &ksPProp.Property,
        sizeof(KSP_PIN),
        NULL,
        0,
        &cbMultipleItem);

    if (SUCCEEDED(hr))
    {
        *ppKsMultipleItem = (PKSMULTIPLE_ITEM) new BYTE[cbMultipleItem];
        if (NULL == ppKsMultipleItem)
        {
            hr = E_OUTOFMEMORY;
        }
        else
        {
            hr = SyncIoctl(
                m_handle,
                IOCTL_KS_PROPERTY,
               &ksPProp,
               sizeof(KSP_PIN),
               (PVOID)*ppKsMultipleItem,
               cbMultipleItem,
               &ulReturned);
        }
    }
    TRACE_LEAVE_HRESULT(hr);
    return hr;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsFilter::EnumerateNodes()
//
//  Routine Description:
//      Enumerates nodes
//
//  Arguments:
//      None
//
//
//  Return Value:
//
//     S_OK on success
//

HRESULT CKsFilter::EnumerateNodes(void)
{
    TRACE_ENTER();
    HRESULT hr = S_OK;

    // Clear the existing node list
    CKsNode *pKsNode;
    while( m_listNodes.RemoveHead(&pKsNode) )
    {
        delete pKsNode;
    }

    PKSMULTIPLE_ITEM    pkmiTopoNodes = NULL;

    hr = GetPropertyMulti(
            KSPROPSETID_Topology,
            KSPROPERTY_TOPOLOGY_NODES,
            &pkmiTopoNodes
        );

    if (FAILED(hr))
    {
        DebugPrintf(TRACE_NORMAL,TEXT( "Failed to get property KSPROPSETID_Topology.KSPROPERTY_TOPOLOGY_NODES"));
    }
    else
    {
        if (pkmiTopoNodes)
        {
            ULONG cNodes = pkmiTopoNodes->Count;

            // Point to immediately following pkmiTopoNodes
            GUID* argguidNodes = (GUID*)(pkmiTopoNodes + 1);

            // Iterate through all the nodes
            for(ULONG nNode = 0; nNode < cNodes; nNode++)
            {
                CKsNode* pnewNode = new CKsNode(nNode, argguidNodes[nNode], &hr);
                if (pnewNode)
                {
                    if (SUCCEEDED(hr))
                    {
                        // Add the node to the list
                        if (NULL==m_listNodes.AddTail(pnewNode))
                        {
                            hr = E_OUTOFMEMORY;
                        }
                    }

                    if (FAILED(hr))
                    {
                        delete pnewNode;
                    }
                }
                // Don't need to set hr if we got a NULL result, as the check below will fail
                // and set hr to E_FAIL.
            }

            if (m_listNodes.GetCount() != cNodes)
            {
                hr = E_FAIL;

                while( m_listNodes.RemoveHead(&pKsNode) )
                {
                    delete pKsNode;
                }
            }
        }
    }

    delete[] (BYTE*)pkmiTopoNodes;

    TRACE_LEAVE_HRESULT(hr);
    return hr;
}


code:
//**@@@*@@@****************************************************
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//**@@@*@@@****************************************************

//
// FileName:    filter.h
//
// Abstract:
//      This is the header file for C++ classes that expose
//      functionality of KS filters
//

#pragma once
#ifndef __KSFILTER_H
#define __KSFILTER_H

// Forward Declarations
class CKsPin;
class CKsNode;

////////////////////////////////////////////////////////////////////////////////
//
//  class CKsFilter
//
//  Class Description:
//      This is the base class for classes that proxy Ks filters from user mode.
//      Basic usage is
//          instantiate a CKsFilter (or derived class)
//          call Instantiate, which creates a file object (instantiates the KS filter)
//                  whose handle is stored as m_handle
//          call EnumeratePins, EnumerateNodes, to deduce the filter's topology
//          call CKsIrpTarget functions to get/set properties
//
//
//

class CKsFilter : public CKsIrpTarget
{
public:
    CKsFilter(
        IN LPCTSTR pszName,
        OUT HRESULT* phr);

    virtual ~CKsFilter(void);
    virtual HRESULT Instantiate(void);
    virtual HRESULT EnumerateNodes(void);
    virtual HRESULT EnumeratePins(void);

    HRESULT GetPinPropertySimple(
        IN  ULONG   nPinID,
        IN  REFGUID guidPropertySet,
        IN  ULONG   nProperty,
        OUT PVOID   pvValue,
        OUT ULONG   cbValue);

    HRESULT GetPinPropertyMulti(
        IN  ULONG   nPinID,
        IN  REFGUID guidPropertySet,
        IN  ULONG   nProperty,
        OUT PKSMULTIPLE_ITEM* ppKsMultipleItem OPTIONAL);

protected:

    HRESULT ClassifyPins();

     // Lists of nodes
    TList<CKsNode>      m_listNodes;

     // This is the "ROOT LIST" for all pins
    TList<CKsPin>   m_listPins;

    // These lists only contain copies of the pointers in m_listPins.
    // Don't delete the memory that they point
    TList<CKsPin>   m_listRenderSinkPins;
    TList<CKsPin>   m_listRenderSourcePins;
    TList<CKsPin>   m_listCaptureSinkPins;
    TList<CKsPin>   m_listCaptureSourcePins;
    TList<CKsPin>   m_listNoCommPins;
    ETechnology m_eType;

private:
    TCHAR       m_szFilterName[MAX_PATH];   // Filter Path

    virtual HRESULT DestroyLists(void);

    HRESULT InternalInit(void);

// Friends
friend class CKsPin;
friend class CKsAudPin;
friend class CKsNode;

};

typedef CKsFilter *             PCKsFilter;

#endif //__KSFILTER_H


code:
//**@@@*@@@****************************************************
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//**@@@*@@@****************************************************

//
// FileName:    irptgt.cpp
//
// Abstract:
//      This is the implementation file for the C++ base class which abstracts
//      common functionality in CKsFilter and CKsPin classes
//

#include "kssample.h"

// String's for logging.  These match up with the enumerations in kssample.h
LPCSTR gpstrKsTechnology[] = {"Unknown","PCM Audio Render","PCM Audio Capture"};

////////////////////////////////////////////////////////////////////////////////
//
//  CKsIrpTarget::CKsIrpTarget()
//
//  Routine Description:
//
//      CKsIrpTarget Constructor.
//
//  Arguments:
//
//      None
//
//  Return Value:
//
//     None
//

CKsIrpTarget::CKsIrpTarget(HANDLE handle)
    : m_handle(handle)
{
    TRACE_ENTER();

    TRACE_LEAVE();
    return;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsIrpTarget::CKsIrpTarget()
//
//  Routine Description:
//
//      CKsIrpTarget Constructor.
//
//  Arguments:
//
//      None
//
//  Return Value:
//
//     None
//

HANDLE CKsIrpTarget::GetHandle()
{
    TRACE_ENTER();

    TRACE_LEAVE();
    return m_handle;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsIrpTarget::IsValidHandle()
//
//  Routine Description:
//
//      Quick and Dirty check to see if the handle is good.  Only checks against
//      a small number of known bad values.
//
//  Arguments:
//
//      HANDLE
//
//  Return Value:
//
//      Returns TRUE unless the handle is NULL or INVALID_HANDLE_VALUE
//

BOOL CKsIrpTarget::IsValidHandle(HANDLE handle)
{
    TRACE_ENTER();
    BOOL bRet;

    bRet = !((handle == NULL) || (handle == INVALID_HANDLE_VALUE));

    TRACE_LEAVE();
    return bRet;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsIrpTarget::SafeCloseHandle()
//
//  Routine Description:
//
//      Safely closes a file handle
//
//  Arguments:
//
//      HANDLE
//
//  Return Value:
//
//     None
//

BOOL CKsIrpTarget::SafeCloseHandle(HANDLE &handle)
{
    TRACE_ENTER();
    BOOL bRet;
    bRet = TRUE;

    if (IsValidHandle(handle))
    {
        bRet = CloseHandle(handle);
        handle = INVALID_HANDLE_VALUE;
    }

    TRACE_LEAVE();
    return bRet;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsIrpTarget::Close()
//
//  Routine Description:
//
//      Close the Irp Target
//
//  Arguments:
//
//      None
//
//  Return Value:
//
//     None
//

BOOL CKsIrpTarget::Close()
{
    TRACE_ENTER();
    BOOL bRet = TRUE;

    bRet = SafeCloseHandle(m_handle);

    TRACE_LEAVE();
    return bRet;
}
////////////////////////////////////////////////////////////////////////////////
//
//  CKsIrpTarget::xxx()
//
//  Routine Description:
//
//      SyncIoctl
//
//  Arguments:
//
//      IN  HANDLE  handle -- The file handle to send the IOCTL to
//      IN  ULONG   ulIoctl -- The IOCTL to send
//      IN  PVOID   pvInBuffer -- Pointer to the input buffer
//      IN  ULONG   cbInBuffer -- Size in bytes of the input buffer
//      OUT PVOID   pvOutBuffer -- Pointer to the output buffer
//      OUT ULONG   cbOutBuffer -- Size in bytes of the output buffer
//      OUT PULONG  pulBytesReturned -- The number of bytes written to the
//          output buffer.
//
//  Return Value:
//
//     S_OK on success
//

HRESULT CKsIrpTarget::SyncIoctl(
        IN  HANDLE  handle,
        IN  ULONG   ulIoctl,
        IN  PVOID   pvInBuffer,
        IN  ULONG   cbInBuffer,
        OUT PVOID   pvOutBuffer,
        OUT ULONG   cbOutBuffer,
        OUT PULONG  pulBytesReturned)
{
    TRACE_ENTER();
    HRESULT hr = S_OK;
    OVERLAPPED overlapped;
        BOOL fRes = TRUE;
        ULONG ulBytesReturned;

    if (!IsValidHandle(handle))
    {
        hr = E_FAIL;
        DebugPrintf(TRACE_ERROR,TEXT("CKsIrpTarget::SyncIoctl Invalid Handle"));
    }

    if (!pulBytesReturned)
    {
        pulBytesReturned = &ulBytesReturned;
    }

    if (SUCCEEDED(hr))
    {
        ZeroMemory(&overlapped,sizeof(overlapped));
        overlapped.hEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
        if (!overlapped.hEvent)
        {
            hr = E_OUTOFMEMORY;
            DebugPrintf(TRACE_ERROR,TEXT("CKsIrpTarget::SyncIoctl CreateEvent failed"));
        }
        else
        {
            // Flag the event by setting the low-order bit so we
            // don't get completion port notifications.
            // Really! - see the description of the lpOverlapped parameter in
            // the docs for GetQueuedCompletionStatus
            overlapped.hEvent = (HANDLE)((DWORD_PTR)overlapped.hEvent | 0x1);
        }
    }

    if (SUCCEEDED(hr))
    {
        fRes = DeviceIoControl(handle, ulIoctl, pvInBuffer, cbInBuffer, pvOutBuffer, cbOutBuffer, pulBytesReturned, &overlapped);
        if (!fRes)
        {

            DWORD dwError;
            dwError = GetLastError();
            if (ERROR_IO_PENDING == dwError)
            {
                DWORD dwWait;
                // Wait for completion
                dwWait = ::WaitForSingleObject(overlapped.hEvent,INFINITE);
                assert(WAIT_OBJECT_0 == dwWait);
                if (dwWait != WAIT_OBJECT_0)
                {
                    hr = E_FAIL;
                    DebugPrintf(TRACE_ERROR,TEXT("CKsIrpTarget::SyncIoctl WaitForSingleObject failed dwWait:0x%08x"),dwWait);
                }
            }
            else if (((ERROR_INSUFFICIENT_BUFFER == dwError) || (ERROR_MORE_DATA == dwError)) &&
                (IOCTL_KS_PROPERTY == ulIoctl) &&
                (cbOutBuffer == 0))
            {
                hr = S_OK;
                fRes = TRUE;
            }
            else
            {
                hr = E_FAIL;
            }
        }
        if (!fRes) *pulBytesReturned = 0;
        SafeCloseHandle(overlapped.hEvent);
    }

    TRACE_LEAVE_HRESULT(hr);
    return hr;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsIrpTarget::PropertySetSupport()
//
//  Routine Description:
//      Query to see if a property set is supported
//
//  Arguments:
//      The GUID of the property set
//
//  Return Value:
//
//      S_OK if the Property set is supported
//      S_FALSE if the property set is unsupported
//

HRESULT CKsIrpTarget::PropertySetSupport(
    IN  REFGUID  guidPropertySet)
{
    TRACE_ENTER();
    HRESULT hr = S_OK;

    ULONG ulReturned;
    KSPROPERTY ksProperty;

    ZeroMemory(&ksProperty,sizeof(ksProperty));

    ksProperty.Set = guidPropertySet;
    ksProperty.Id = 0;
    ksProperty.Flags = KSPROPERTY_TYPE_SETSUPPORT;

    hr = SyncIoctl(
        m_handle,
        IOCTL_KS_PROPERTY,
        &ksProperty,
        sizeof(ksProperty),
        NULL,
        0,
        &ulReturned);

    TRACE_LEAVE_HRESULT(hr);
    return hr;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsIrpTarget::PropertyBasicSupport()
//
//  Routine Description:
//      Get the basic support information for this KSPROPERTY
//
//  Arguments:
//      guidPropetySet -- The guid of the property set
//      nProperty   -- The property in the property set
//      pdwSupport -- The support information for the property
//
//  Return Value:
//
//     S_OK on success
//

HRESULT CKsIrpTarget::PropertyBasicSupport(
    IN  REFGUID guidPropertySet,
    IN  ULONG   nProperty,
    OUT PDWORD  pdwSupport
)
{
    TRACE_ENTER();
    HRESULT hr = S_OK;

    ULONG ulReturned;
    KSPROPERTY ksProperty;

    ZeroMemory(&ksProperty,sizeof(ksProperty));

    ksProperty.Set = guidPropertySet;
    ksProperty.Id = nProperty;
    ksProperty.Flags = KSPROPERTY_TYPE_BASICSUPPORT;

    hr = SyncIoctl(
            m_handle,
            IOCTL_KS_PROPERTY,
            &ksProperty,
            sizeof(ksProperty),
            pdwSupport,
            sizeof(DWORD),
            &ulReturned);

    TRACE_LEAVE_HRESULT(hr);
    return hr;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsIrpTarget::GetPropertySimple()
//
//  Routine Description:
//      Gets a simple property;
//
//  Arguments:
//      All the stuff for a property call
//
//  Return Value:
//     S_OK on success
//

HRESULT CKsIrpTarget::GetPropertySimple(
    IN          REFGUID guidPropertySet,
    IN          ULONG   nProperty,
    OUT         PVOID   pvValue,
    OUT         ULONG   cbValue,
    OPTIONAL IN PVOID   pvInstance,
    OPTIONAL IN ULONG   cbInstance)
{
    TRACE_ENTER();
    HRESULT hr = S_OK;
    ULONG ulReturned = 0;
    PKSPROPERTY pKsProperty = NULL;
    ULONG cbProperty = 0;

    cbProperty = sizeof(KSPROPERTY) + cbInstance;
    pKsProperty = (PKSPROPERTY)new BYTE[cbProperty];
    if (NULL == pKsProperty)
    {
        hr = E_OUTOFMEMORY;
    }

    if (SUCCEEDED(hr))
    {
        ZeroMemory(pKsProperty,sizeof(*pKsProperty));
        pKsProperty->Set = guidPropertySet;
        pKsProperty->Id = nProperty;
        pKsProperty->Flags = KSPROPERTY_TYPE_GET;

        if (pvInstance)
        {
            CopyMemory(reinterpret_cast<BYTE*>(pKsProperty) + sizeof(KSPROPERTY),pvInstance,cbInstance);
        }

        hr = SyncIoctl(
                m_handle,
                IOCTL_KS_PROPERTY,
                pKsProperty,
                cbProperty,
                pvValue,
                cbValue,
                &ulReturned);
    }

    //cleanup memory
    delete[] (BYTE*)pKsProperty;
    pKsProperty = NULL;

    TRACE_LEAVE_HRESULT(hr);
    return hr;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsIrpTarget::GetPropertyMulti()
//
//  Routine Description:
//      MultipleItem request.  The function allocates memory for the
//      caller.  It is the caller's responsiblity to free this memory
//
//  Arguments:
//
//      HANDLE
//
//  Return Value:
//
//     S_OK on success
//

HRESULT CKsIrpTarget::GetPropertyMulti(
    IN  REFGUID             guidPropertySet,
    IN  ULONG               nProperty,
    OUT PKSMULTIPLE_ITEM*   ppKsMultipleItem)
{
    TRACE_ENTER();
    HRESULT hr = S_OK;

    ULONG cbMultipleItem = 0;
    ULONG ulReturned = 0;
    KSPROPERTY ksProperty;

    ZeroMemory(&ksProperty, sizeof(ksProperty));
    ksProperty.Set = guidPropertySet;
    ksProperty.Id = nProperty;
    ksProperty.Flags = KSPROPERTY_TYPE_GET;

    hr = SyncIoctl(
            m_handle,
            IOCTL_KS_PROPERTY,
            &ksProperty,
            sizeof(KSPROPERTY),
            NULL,
            0,
            &cbMultipleItem);
    if (SUCCEEDED(hr) && cbMultipleItem)
    {
        *ppKsMultipleItem = (PKSMULTIPLE_ITEM) new BYTE[cbMultipleItem];
        if (NULL == *ppKsMultipleItem)
        {
            hr = E_OUTOFMEMORY;
        }
    }

    if (SUCCEEDED(hr) && cbMultipleItem)
    {
        hr = SyncIoctl(
                m_handle,
                IOCTL_KS_PROPERTY,
                &ksProperty,
                sizeof(ksProperty),
                reinterpret_cast<VOID*>(*ppKsMultipleItem),
                cbMultipleItem,
                &ulReturned);
    }

    TRACE_LEAVE_HRESULT(hr);
    return hr;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsIrpTarget::GetPropertyMulti()
//
//  Routine Description:
//      MultipleItem request for when the input is not a property
//      The function allocates memory for the
//      caller.  It is the caller's responsiblity to free this memory
//
//  Arguments:
//
//      HANDLE
//
//  Return Value:
//
//     S_OK on success
//

HRESULT CKsIrpTarget::GetPropertyMulti(
    IN  REFGUID             guidPropertySet,
    IN  ULONG               nProperty,
    IN  PVOID               pvData,
    IN  ULONG               cbData,
    OUT PKSMULTIPLE_ITEM*   ppKsMultipleItem)
{
    TRACE_ENTER();
    HRESULT hr = S_OK;

    ULONG cbMultipleItem = 0;
    ULONG ulReturned = 0;
    KSPROPERTY ksProperty;

    ZeroMemory(&ksProperty, sizeof(ksProperty));
    ksProperty.Set = guidPropertySet;
    ksProperty.Id = nProperty;
    ksProperty.Flags = KSPROPERTY_TYPE_GET;

    hr = SyncIoctl(
            m_handle,
            IOCTL_KS_PROPERTY,
            &ksProperty,
            sizeof(KSPROPERTY),
            NULL,
            0,
            &cbMultipleItem);
    if (SUCCEEDED(hr) && cbMultipleItem)
    {
        *ppKsMultipleItem = (PKSMULTIPLE_ITEM) new BYTE[cbMultipleItem];
        if (NULL == *ppKsMultipleItem)
        {
            hr = E_OUTOFMEMORY;
        }
    }

    if (SUCCEEDED(hr) && cbMultipleItem)
    {
        hr = SyncIoctl(
                m_handle,
                IOCTL_KS_PROPERTY,
                (PKSPROPERTY) pvData,
                cbData,
                reinterpret_cast<VOID*>(*ppKsMultipleItem),
                cbMultipleItem,
                &ulReturned);
    }

    TRACE_LEAVE_HRESULT(hr);
    return hr;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsIrpTarget::GetNodePropertySimple()
//
//  Routine Description:
//      Gets a simple node property
//
//  Arguments:
//      All the stuff for a property call
//
//  Return Value:
//     S_OK on success
//

HRESULT CKsIrpTarget::GetNodePropertySimple(
    IN  ULONG               nNodeID,
    IN  REFGUID             guidPropertySet,
    IN  ULONG               nProperty,
    OUT PVOID               pvValue,
    IN  ULONG               cbValue,
    OPTIONAL IN PVOID   pvInstance,
    OPTIONAL IN ULONG   cbInstance)
{
    TRACE_ENTER();
    HRESULT hr = S_OK;
    ULONG ulReturned = 0;
    PKSNODEPROPERTY pKsNodeProperty = NULL;
    ULONG cbProperty = 0;

    cbProperty = sizeof(KSNODEPROPERTY) + cbInstance;
    pKsNodeProperty = (PKSNODEPROPERTY)new BYTE[cbProperty];
    if (NULL == pKsNodeProperty)
    {
        hr = E_OUTOFMEMORY;
    }

    if (SUCCEEDED(hr))
    {
        ZeroMemory(pKsNodeProperty,sizeof(*pKsNodeProperty));
        pKsNodeProperty->Property.Set = guidPropertySet;
        pKsNodeProperty->Property.Id = nProperty;
        pKsNodeProperty->Property.Flags = KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_TOPOLOGY;
        pKsNodeProperty->NodeId = nNodeID;
        pKsNodeProperty->Reserved = 0;

        if (pvInstance)
        {
            CopyMemory(reinterpret_cast<BYTE*>(pKsNodeProperty) + sizeof(KSNODEPROPERTY),pvInstance,cbInstance);
        }

        hr = SyncIoctl(
                m_handle,
                IOCTL_KS_PROPERTY,
                pKsNodeProperty,
                cbProperty,
                pvValue,
                cbValue,
                &ulReturned);
    }

    //cleanup memory
    delete[] (BYTE*)pKsNodeProperty;
    pKsNodeProperty = NULL;

    TRACE_LEAVE_HRESULT(hr);
    return hr;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsIrpTarget::GetNodePropertyChannel()
//
//  Routine Description:
//      Gets a simple node channel property
//
//  Arguments:
//      All the stuff for a property call
//
//  Return Value:
//     S_OK on success
//

HRESULT CKsIrpTarget::GetNodePropertyChannel(
    IN  ULONG               nNodeID,
    IN  ULONG               nChannel,
    IN  REFGUID             guidPropertySet,
    IN  ULONG               nProperty,
    OUT PVOID               pvValue,
    IN  ULONG               cbValue,
    OPTIONAL IN PVOID   pvInstance,
    OPTIONAL IN ULONG   cbInstance)
{
    TRACE_ENTER();
    HRESULT hr = S_OK;
    ULONG ulReturned = 0;
    PKSNODEPROPERTY_AUDIO_CHANNEL pKsNodePropertyChannel = NULL;
    ULONG cbProperty = 0;

    cbProperty = sizeof(KSNODEPROPERTY_AUDIO_CHANNEL) + cbInstance;
    pKsNodePropertyChannel = (PKSNODEPROPERTY_AUDIO_CHANNEL)new BYTE[cbProperty];
    if (NULL == pKsNodePropertyChannel)
    {
        hr = E_OUTOFMEMORY;
    }

    if (SUCCEEDED(hr))
    {
        ZeroMemory(pKsNodePropertyChannel,sizeof(*pKsNodePropertyChannel));
        pKsNodePropertyChannel->NodeProperty.Property.Set = guidPropertySet;
        pKsNodePropertyChannel->NodeProperty.Property.Id = nProperty;
        pKsNodePropertyChannel->NodeProperty.Property.Flags = KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_TOPOLOGY;
        pKsNodePropertyChannel->NodeProperty.NodeId = nNodeID;
        pKsNodePropertyChannel->NodeProperty.Reserved = 0;
        pKsNodePropertyChannel->Channel = nChannel;
        pKsNodePropertyChannel->Reserved = 0;

        if (pvInstance)
        {
            CopyMemory(reinterpret_cast<BYTE*>(pKsNodePropertyChannel) + sizeof(KSNODEPROPERTY_AUDIO_CHANNEL),pvInstance,cbInstance);
        }

        hr = SyncIoctl(
                m_handle,
                IOCTL_KS_PROPERTY,
                pKsNodePropertyChannel,
                cbProperty,
                pvValue,
                cbValue,
                &ulReturned);
    }

    //cleanup memory
    delete[] (BYTE*)pKsNodePropertyChannel;
    pKsNodePropertyChannel = NULL;

    TRACE_LEAVE_HRESULT(hr);
    return hr;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsIrpTarget::SetPropertySimple()
//
//  Routine Description:
//
//      Set the value of a simple (non-multi) property
//
//  Arguments:
//
//      HANDLE
//
//  Return Value:
//
//     S_OK on success
//

HRESULT CKsIrpTarget::SetPropertySimple(
    IN          REFGUID guidPropertySet,
    IN          ULONG   nProperty,
    OUT         PVOID   pvValue,
    OUT         ULONG   cbValue,
    OPTIONAL IN PVOID   pvInstance,
    OPTIONAL IN ULONG   cbInstance)
{
    TRACE_ENTER();
    HRESULT hr = S_OK;
    ULONG       ulReturned  = 0;
    PKSPROPERTY pksProperty = NULL;
    ULONG       cbProperty  = 0;

    cbProperty = sizeof(KSPROPERTY) + cbInstance;
    pksProperty = (PKSPROPERTY)new BYTE[cbProperty];
    if (NULL == pksProperty)
    {
        hr = E_OUTOFMEMORY;
    }

    if (SUCCEEDED(hr))
    {
        pksProperty->Set    = guidPropertySet;
        pksProperty->Id     = nProperty;
        pksProperty->Flags  = KSPROPERTY_TYPE_SET;

        if (pvInstance)
        {
            memcpy((PBYTE)pksProperty + sizeof(KSPROPERTY), pvInstance, cbInstance);
        }

        hr = SyncIoctl(
                m_handle,
                IOCTL_KS_PROPERTY,
                pksProperty,
                cbProperty,
                pvValue,
                cbValue,
                &ulReturned);
    }

    //cleanup memory
    delete[] (BYTE*)pksProperty;
    pksProperty = NULL;

    TRACE_LEAVE_HRESULT(hr);
    return hr;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsIrpTarget::SetPropertyMulti()
//
//  Routine Description:
//
//      Blah Blah Blah
//
//  Arguments:
//
//      HANDLE
//
//  Return Value:
//
//     S_OK on success
//

HRESULT CKsIrpTarget::SetPropertyMulti(
    IN  REFGUID             guidPropertySet,
    IN  ULONG               nProperty,
    OUT PKSMULTIPLE_ITEM*   ppKsMultipleItem)
{
    TRACE_ENTER();
    HRESULT hr = S_OK;
    ULONG       cbMultipleItem = 0;
    ULONG       ulReturned = 0;
    KSPROPERTY  ksProperty;

    ksProperty.Set    = guidPropertySet;
    ksProperty.Id     = nProperty;
    ksProperty.Flags  = KSPROPERTY_TYPE_SET;

    hr = SyncIoctl(
            m_handle,
            IOCTL_KS_PROPERTY,
            &ksProperty,
            sizeof(KSPROPERTY),
            NULL,
            0,
            &cbMultipleItem);

    if (SUCCEEDED(hr))
    {
        *ppKsMultipleItem = (PKSMULTIPLE_ITEM)LocalAlloc(LPTR, cbMultipleItem);

        hr = SyncIoctl (
                m_handle,
                IOCTL_KS_PROPERTY,
                &ksProperty,
                sizeof(KSPROPERTY),
                (PVOID)*ppKsMultipleItem,
                cbMultipleItem,
                &ulReturned);
    }

    TRACE_LEAVE_HRESULT(hr);
    return hr;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsIrpTarget::SetNodePropertySimple()
//
//  Routine Description:
//
//      Set the value of a simple (non-multi) node property
//
//  Arguments:
//
//      All the stuff for a property call
//
//  Return Value:
//
//     S_OK on success
//

HRESULT CKsIrpTarget::SetNodePropertySimple(
    IN          ULONG   nNodeID,
    IN          REFGUID guidPropertySet,
    IN          ULONG   nProperty,
    OUT         PVOID   pvValue,
    OUT         ULONG   cbValue,
    OPTIONAL IN PVOID   pvInstance,
    OPTIONAL IN ULONG   cbInstance)
{
    TRACE_ENTER();
    HRESULT hr = S_OK;
    ULONG       ulReturned  = 0;
    PKSNODEPROPERTY pKsNodeProperty = NULL;
    ULONG       cbProperty  = 0;

    cbProperty = sizeof(KSNODEPROPERTY) + cbInstance;
    pKsNodeProperty = (PKSNODEPROPERTY)new BYTE[cbProperty];

    if (NULL == pKsNodeProperty)
    {
        hr = E_OUTOFMEMORY;
    }

    if (SUCCEEDED(hr))
    {
        pKsNodeProperty->Property.Set    = guidPropertySet;
        pKsNodeProperty->Property.Id     = nProperty;
        pKsNodeProperty->Property.Flags  = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY;
        pKsNodeProperty->NodeId          = nNodeID;
        pKsNodeProperty->Reserved        = 0;

        if (pvInstance)
        {
            memcpy((PBYTE)pKsNodeProperty + sizeof(KSNODEPROPERTY), pvInstance, cbInstance);
        }

        hr = SyncIoctl(
                m_handle,
                IOCTL_KS_PROPERTY,
                pKsNodeProperty,
                cbProperty,
                pvValue,
                cbValue,
                &ulReturned);
    }

    //cleanup memory
    delete[] (BYTE*)pKsNodeProperty;
    pKsNodeProperty = NULL;

    TRACE_LEAVE_HRESULT(hr);
    return hr;
}

////////////////////////////////////////////////////////////////////////////////
//
//  CKsIrpTarget::SetNodePropertyChannel()
//
//  Routine Description:
//
//      Set the value of a simple (non-multi) node channel property
//
//  Arguments:
//
//      All the stuff for a property call
//
//  Return Value:
//
//     S_OK on success
//

HRESULT CKsIrpTarget::SetNodePropertyChannel(
    IN          ULONG   nNodeID,
    IN          ULONG   nChannel,
    IN          REFGUID guidPropertySet,
    IN          ULONG   nProperty,
    OUT         PVOID   pvValue,
    OUT         ULONG   cbValue,
    OPTIONAL IN PVOID   pvInstance,
    OPTIONAL IN ULONG   cbInstance)
{
    TRACE_ENTER();
    HRESULT hr = S_OK;
    ULONG       ulReturned  = 0;
    PKSNODEPROPERTY_AUDIO_CHANNEL pKsNodePropertyChannel = NULL;
    ULONG       cbProperty  = 0;

    cbProperty = sizeof(KSNODEPROPERTY_AUDIO_CHANNEL) + cbInstance;
    pKsNodePropertyChannel = (PKSNODEPROPERTY_AUDIO_CHANNEL)new BYTE[cbProperty];

    if (NULL == pKsNodePropertyChannel)
    {
        hr = E_OUTOFMEMORY;
    }

    if (SUCCEEDED(hr))
    {
        pKsNodePropertyChannel->NodeProperty.Property.Set    = guidPropertySet;
        pKsNodePropertyChannel->NodeProperty.Property.Id     = nProperty;
        pKsNodePropertyChannel->NodeProperty.Property.Flags  = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY;
        pKsNodePropertyChannel->NodeProperty.NodeId          = nNodeID;
        pKsNodePropertyChannel->NodeProperty.Reserved        = 0;
        pKsNodePropertyChannel->Channel         = nChannel;
        pKsNodePropertyChannel->Reserved        = 0;

        if (pvInstance)
        {
            memcpy((PBYTE)pKsNodePropertyChannel + sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), pvInstance, cbInstance);
        }

        hr = SyncIoctl(
                m_handle,
                IOCTL_KS_PROPERTY,
                pKsNodePropertyChannel,
                cbProperty,
                pvValue,
                cbValue,
                &ulReturned);
    }

    //cleanup memory
    delete[] (BYTE*)pKsNodePropertyChannel;
    pKsNodePropertyChannel = NULL;

    TRACE_LEAVE_HRESULT(hr);
    return hr;
}


code:
//**@@@*@@@****************************************************
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//**@@@*@@@****************************************************

//
// FileName:    irptgt.h
//
// Abstract:
//      This is the header file for the C++ base class which abstracts
//      common functionality in CKsFilter and CKsPin classes
//
#pragma once
#ifndef __KSIRPTGT_H
#define __KSIRPTGT_H

////////////////////////////////////////////////////////////////////////////////
//
//  class CKsIrpTarget
//
//  Class Description:
//      This is a base class for controlling Ks file objects, i.e. filters and pins\
//      CKsFilter and CKsPin derive from this class
//

class CKsIrpTarget
{

public:

    // Constructor
    CKsIrpTarget(
            IN  HANDLE handle);

    // Static Utility Functions

    static HRESULT SyncIoctl(
            IN  HANDLE  handle,
            IN  ULONG   ulIoctl,
            IN  PVOID   pvInBuffer,
            IN  ULONG   cbInBuffer,
            OUT PVOID   pvOutBuffer,
            OUT ULONG   cbOutBuffer,
            OUT PULONG  pulBytesReturned);

   static BOOL SafeCloseHandle(HANDLE&);
   static BOOL IsValidHandle(HANDLE);
   HANDLE GetHandle(void);
   BOOL Close(void);

 // Protected Utility Functions available to derived classes
protected:

    // Protected Data Members
    HANDLE  m_handle;     // allocated handle of the filter instance

    // Support
    HRESULT PropertySetSupport(
        IN REFGUID  guidPropertySet);

    HRESULT PropertyBasicSupport(
        IN  REFGUID guidPropertySet,
        IN  ULONG   nPropertySet,
        OUT PDWORD  pdwSupport);

    // GET
    HRESULT GetPropertySimple(
        IN  REFGUID guidPropertySet,
        IN  ULONG   nProperty,
        OUT PVOID   pvValue,
        IN  ULONG   cbValue,
        OPTIONAL IN PVOID pvInstance = NULL,
        OPTIONAL IN ULONG cbInstance = 0);

    HRESULT GetPropertyMulti(
        IN  REFGUID guidPropertySet,
        IN  ULONG   nProperty,
        OUT PKSMULTIPLE_ITEM* ppKsMultipleItem);

    HRESULT GetPropertyMulti(
        IN  REFGUID guidPropertySet,
        IN  ULONG   nProperty,
        IN  PVOID   pvData,
        IN  ULONG   cbData,
        OUT PKSMULTIPLE_ITEM* ppksMultipleItem);

    HRESULT GetNodePropertySimple(
        IN  ULONG               nNodeID,
        IN  REFGUID             guidPropertySet,
        IN  ULONG               nProperty,
        OUT PVOID               pvValue,
        IN  ULONG               cbValue,
        OPTIONAL IN PVOID       pvInstance = NULL,
        OPTIONAL IN ULONG       cbInstance = 0);

    HRESULT GetNodePropertyChannel(
        IN  ULONG               nNodeID,
        IN  ULONG               nChannel,
        IN  REFGUID             guidPropertySet,
        IN  ULONG               nProperty,
        OUT PVOID               pvValue,
        IN  ULONG               cbValue,
        OPTIONAL IN PVOID       pvInstance = NULL,
        OPTIONAL IN ULONG       cbInstance = 0);

    // Set
    HRESULT SetPropertySimple(
        IN  REFGUID guidPropertySet,
        IN  ULONG   nProperty,
        OUT PVOID   pvValue,
        IN  ULONG   cbValue,
        OPTIONAL IN PVOID pvInstance = NULL,
        OPTIONAL IN ULONG cbInstance = 0);

    HRESULT SetPropertyMulti(
        IN  REFGUID guidPropertySet,
        IN  ULONG   nProperty,
        OUT PKSMULTIPLE_ITEM* ppKsMultipleItem);

    HRESULT SetNodePropertySimple(
        IN  ULONG               nNodeID,
        IN  REFGUID             guidPropertySet,
        IN  ULONG               nProperty,
        IN  PVOID               pvValue,
        IN  ULONG               cbValue,
        OPTIONAL IN PVOID       pvInstance = NULL,
        OPTIONAL IN ULONG       cbInstance = 0);

    HRESULT SetNodePropertyChannel(
        IN  ULONG               nNodeID,
        IN  ULONG               nChannel,
        IN  REFGUID             guidPropertySet,
        IN  ULONG               nProperty,
        IN  PVOID               pvValue,
        IN  ULONG               cbValue,
        OPTIONAL IN PVOID       pvInstance = NULL,
        OPTIONAL IN ULONG       cbInstance = 0);

};

#endif //__KSIRPTGT_H


code:
//**@@@*@@@****************************************************
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//**@@@*@@@****************************************************

//
// FileName:    kssample.h
//
// Abstract:
//      All of the necessary includes in one place
//

#pragma once
#ifndef __COMMONKS_H
#define __COMMONKS_H

#define _WIN32_WINNT 0x0501
#ifdef WINVER
#undef WINVER
#endif
#define WINVER 0x0501

#include <windows.h>
#include <ks.h>
#include <ksmedia.h>
#include <tchar.h>
#include <assert.h>
#include <stdio.h>
#include <shlobj.h>
#include <winioctl.h>

#define SAFE_DELETE(x) delete x; x = NULL;

// filter types
typedef enum {eUnknown, eAudRen, eAudCap} ETechnology;

typedef struct
{
    KSP_PIN KsPProp;
    KSMULTIPLE_ITEM KsMultiple;
} INTERSECTION;

#include "tlist.h"
#include "util.h"
#include "irptgt.h"
#include "filter.h"
#include "pin.h"
#include "node.h"
#include "enum.h"
#include "audfilter.h"
#include "audpin.h"

#endif //__COMMONKS_H