Click here to Skip to main content
15,885,435 members
Articles / Desktop Programming / WTL

Multidevice ASIO output plugin for WinAMP

Rate me:
Please Sign up or sign in to vote.
4.80/5 (9 votes)
13 Feb 2009CDDL27 min read 48.1K   728   23  
A tiny WinAMP output DLL that uses a C++ replacement of the official ASIO SDK that supports multiple ASIO devices.
#include "Registry.hpp"

#include "debugMacros.hpp"


//************************************
// Method:    SubKeys
// FullName:  SubKeys::SubKeys
// Access:    public 
//************************************

SubKeys::SubKeys( TCHAR const * const subKeyName, HKEY const rootKey )
    :
    parentKey_( subKeyName, rootKey, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE )
{
    VERIFY( ::RegQueryInfoKey( *parentKey_, NULL, NULL, NULL, &numberOfSubKeys_, NULL, NULL, NULL, NULL, NULL, NULL, NULL ) == ERROR_SUCCESS );
}


//************************************
// Method:    SubKeys
// FullName:  SubKeys::SubKeys
// Access:    public 
//************************************

SubKeys::SubKeys( RegistryKey const & parentKey )
    :
    parentKey_( parentKey )
{
    VERIFY( ::RegQueryInfoKey( *parentKey_, NULL, NULL, NULL, &numberOfSubKeys_, NULL, NULL, NULL, NULL, NULL, NULL, NULL ) == ERROR_SUCCESS );
}


//************************************
// Method:    find
// FullName:  SubKeys::find
// Access:    public
//************************************

SubKeys::const_iterator SubKeys::find( TCHAR const * const subKeyName ) const
{
    return find( value_type( subKeyName, std::strlen( subKeyName ) ) );
}


//************************************
// Method:    find
// FullName:  SubKeys::find
// Access:    public
//************************************

SubKeys::const_iterator SubKeys::find( value_type subKeyName ) const
{
    assert( !empty() );

    const_iterator pSubKey( begin() );
    while( pSubKey.currentIndex() < size() )
    {
        if ( ( subKeyName.size() == pSubKey->size() ) && ( std::memcmp( subKeyName.c_str(), pSubKey->c_str(), subKeyName.size() ) == 0 ) )
            break;
        ++pSubKey;
    }

    return pSubKey;
}


//************************************
// Method:    begin
// FullName:  SubKeys::begin
// Access:    public
//************************************

SubKeys::const_iterator SubKeys::begin() const
{
    assert( !empty() );
    return const_iterator( *parentKey_ );
}


//************************************
// Method:    end
// FullName:  SubKeys::end
// Access:    public
//************************************

SubKeys::const_iterator SubKeys::end() const
{
    return const_iterator( *parentKey_, numberOfSubKeys_, false  );
}


//************************************
// Method:    operator[]
// FullName:  SubKeys::operator[]
// Access:    public
//************************************

SubKeys::const_iterator SubKeys::operator[]( difference_type const subKeyIndex ) const
{
    assert( subKeyIndex < size() );
    return const_iterator( *parentKey_, subKeyIndex );
}


//************************************
// Method:    goToIndex
// FullName:  SubKeys::const_iterator::goToIndex
// Access:    private
//************************************
__declspec( noinline )
void SubKeys::const_iterator::goToIndex( unsigned int const keyIndex )
{
    currentSubKeyName_.setLength( sizeof( nameBuffer_ ) );
    LONG const result( ::RegEnumKeyEx( parentKey_, currentSubKeyIndex_ = keyIndex, nameBuffer_, &currentSubKeyName_.size(), NULL, NULL, NULL, NULL ) );
    //  ERROR_NO_MORE_ITEMS is tolerated to enable incrementing to the "end"
    // iterator (one past last) without an assertion failure (the other solution
    // would be to implement lazy value retrieving (instead of immediately in
    // operator ++).
    // (todo) add better error checking and handling here.
    assert( ( result == ERROR_SUCCESS ) || ( result == ERROR_NO_MORE_ITEMS ) );
    result;
}


//************************************
// Method:    const_iterator
// FullName:  SubKeys::const_iterator::const_iterator
// Access:    public
//************************************

SubKeys::const_iterator::const_iterator( HKEY const parentKey, unsigned int const startingSubKeyIndex, bool const readKeyName )
    :
    parentKey_        ( parentKey      ),
    currentSubKeyName_( nameBuffer_, 0 )
{
    assert( parentKey );
    if ( readKeyName )
        goToIndex( startingSubKeyIndex );
    else
        currentSubKeyIndex_ = startingSubKeyIndex;
}


//************************************
// Method:    const_iterator
// FullName:  SubKeys::const_iterator::const_iterator
// Access:    public
//************************************

SubKeys::const_iterator::const_iterator( SubKeys::const_iterator const & source )
{
    *this = source;
}


//************************************
// Method:    operator=
// FullName:  SubKeys::const_iterator::operator=
// Access:    public
//************************************

SubKeys::const_iterator & SubKeys::const_iterator::operator=( SubKeys::const_iterator const & source )
{
    std::memcpy( this, &source, sizeof( source ) - ( sizeof( nameBuffer_ ) - source.currentSubKeyName_.size() - 1 ) );
    (*this).currentSubKeyName_.setString( (*this).nameBuffer_ );
    return *this;
}


//************************************
// Method:    duplicateHandle
// FullName:  RegistryKey::duplicateHandle
// Access:    private 
//************************************

HKEY RegistryKey::duplicateHandle( HKEY const sourceKey )
{
    HKEY tempHandle;
    VERIFY( ( ::RegOpenKeyEx( sourceKey, NULL, 0, 0, &tempHandle ) == ERROR_SUCCESS ) || ( tempHandle == NULL ) );
    return tempHandle;
}


//************************************
// Method:    close
// FullName:  RegistryKey::close
// Access:    private
//************************************

void RegistryKey::close()
{
    VERIFY( ( ::RegCloseKey( hKey_ ) == ERROR_SUCCESS ) || !*this );
}


//************************************
// Method:    operator=
// FullName:  RegistryKey::operator=
// Access:    public
//************************************

RegistryKey & RegistryKey::operator=( RegistryKey const & sourceKey )
{
    close();
    hKey_ = duplicateHandle( *sourceKey );
    return *this;
}


//************************************
// Method:    RegistryKey
// FullName:  RegistryKey::RegistryKey
// Access:    public
//************************************
// (todo) Unify the following two overloads more intelligently.
//************************************

RegistryKey::RegistryKey( char const * const subKeyName, HKEY const rootKey, REGSAM const desiredAccessRights )
{
    if ( desiredAccessRights )
        VERIFY( ::RegOpenKeyEx( rootKey, subKeyName, 0, desiredAccessRights, &hKey_ ) == ERROR_SUCCESS );
    else
        VERIFY( ::RegOpenKey  ( rootKey, subKeyName,                         &hKey_ ) == ERROR_SUCCESS );
}

RegistryKey::RegistryKey( wchar_t const * const subKeyName, HKEY const rootKey, REGSAM const desiredAccessRights )
{
    if ( desiredAccessRights )
        VERIFY( ::RegOpenKeyExW( rootKey, subKeyName, 0, desiredAccessRights, &hKey_ ) == ERROR_SUCCESS );
    else
        VERIFY( ::RegOpenKeyW  ( rootKey, subKeyName,                         &hKey_ ) == ERROR_SUCCESS );
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Common Development and Distribution License (CDDL)


Written By
Software Developer Little Endian Ltd.
Croatia Croatia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions