Click here to Skip to main content
15,886,689 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.
// Registry.hpp : various MS Windows Registry wrappers and helpers.
//
// (todo) add clean and proper ASCII/Unicode versions/overloads.
//
////////////////////////////////////////////////////////////////////////////////

#pragma once

#include "debugMacros.hpp"

#include <iterator>
#include <string>
#ifndef _UNICODE
#define OLE2ANSI
#endif
#include <tchar.h>


// (todo) move to a separate/appropriate module along with other string helpers.
typedef std::basic_string<TCHAR> tstring;


////////////////////////////////////////////////////////////////////////////////
//
//  WinString
//  ---------
//
//  A small helper class used for saving the length of C strings along the
// strings themselves thus avoiding redundant strlen() calls. Useful for many
// Windows API functions that report/return this length.
//
// (todo) currently only a 'helper class', move to a separate/appropriate
//        module.
//
// (todo) perhaps think of a better name for the class.
//
////////////////////////////////////////////////////////////////////////////////

class WinString
{
public:
    WinString() {}
    WinString( TCHAR const * const string, DWORD const length ) : string_( string ), length_( length ) {}

    TCHAR const * c_str  () const { return string_; }
    tstring       stl_str() const { return tstring( c_str(), size() ); }

    DWORD   size() const { return length_; }
    DWORD & size()       { return length_; }

    TCHAR const * begin() const { return c_str(); }
    TCHAR const * end  () const { return c_str() + size(); }

    void setString( TCHAR const * const newString ) { string_ = newString; }
    void setLength( DWORD const newLength )         { length_ = newLength; }

private:
    TCHAR const * string_;
    DWORD         length_;
};


////////////////////////////////////////////////////////////////////////////////
//
//  RegistryKey
//  -----------
//
//  A light RAII wrapper for a registry key (handle).
//
////////////////////////////////////////////////////////////////////////////////

class RegistryKey
{
public:
    RegistryKey( char    const * subKeyName, HKEY rootKey = HKEY_LOCAL_MACHINE, REGSAM desiredAccessRights = 0 );
    RegistryKey( wchar_t const * subKeyName, HKEY rootKey = HKEY_LOCAL_MACHINE, REGSAM desiredAccessRights = 0 );
    RegistryKey( RegistryKey const & sourceKey ) : hKey_( duplicateHandle( *sourceKey ) ) {}
    ~RegistryKey() { close(); }

    RegistryKey & operator=( RegistryKey const & sourceKey );
    HKEY          operator*() const { return hKey_; }

    typedef void (RegistryKey::*unspecified_bool_type)();
    operator unspecified_bool_type() const { return hKey_ ? &RegistryKey::close : 0; }

public:
    static size_t const maximumRegistryKeyNameLength = 255;

private:
    HKEY duplicateHandle( HKEY const sourceKey );
    void close();

private:
    HKEY hKey_;
};



////////////////////////////////////////////////////////////////////////////////
//
//  SubKeys
//  -------
//
//  A wrapper around a registry key (handle) that tries to provide access to its
// subkeys through an STL (random-access) container like interface.
//
////////////////////////////////////////////////////////////////////////////////
//
// (todo) Add (debug) RegNotifyChangeKeyValue() notification to check if someone
//        is modifying the key(s) while they are being read.
//
////////////////////////////////////////////////////////////////////////////////

class SubKeys
{
public:
    typedef WinString const value_type;
    typedef DWORD difference_type;
    typedef DWORD size_type;
    typedef value_type * const_pointer;
    typedef value_type & const_reference;

    class const_iterator;

public:
    SubKeys( RegistryKey const & parentKey );
    SubKeys( TCHAR const * subKeyName, HKEY rootKey = HKEY_LOCAL_MACHINE );

public: // Sequence interface.
    bool      empty() const { return size() == 0     ; }
    size_type size () const { return numberOfSubKeys_; }

    const_iterator begin() const;
    const_iterator end  () const;

    // "Not exactly" standard conformant.
    const_iterator operator[]( difference_type subKeyIndex ) const;

public: // Utility interface.
    RegistryKey const & parentKey() const { return parentKey_; }

    // The following might perform slightly better/produce smaller code than the STL counterparts.
    const_iterator find( value_type    subKeyName ) const;
    const_iterator find( TCHAR const * subKeyName ) const;

    // Feeds the undereferenced iterator to the functor so that it can use the utility interface.
    template<class Functor>
    void for_each( Functor & functor ) const
    {
        const_iterator pSubKey( begin() );
        while( pSubKey.currentIndex() < size() )
        {
            functor( pSubKey );
            ++pSubKey;
        }
    }
    
private:
    RegistryKey     parentKey_;
    difference_type numberOfSubKeys_;
};


////////////////////////////////////////////////////////////////////////////////
//
//  SubKeys::const_iterator
//  -----------------------
//
////////////////////////////////////////////////////////////////////////////////

class SubKeys::const_iterator : public std::iterator<std::random_access_iterator_tag, SubKeys::value_type, SubKeys::difference_type>
{
public: // Random access iterator interface.
    const_iterator( HKEY hParentKey, unsigned int startingSubKeyIndex = 0, bool readKeyName = true );
    const_iterator( const_iterator const & );

    const_iterator & operator++() { goToIndex( ++currentSubKeyIndex_ ); return *this; }
    const_iterator & operator--() { goToIndex( --currentSubKeyIndex_ ); return *this; }

    const_iterator & operator+=( difference_type const offset ) { goToIndex( currentSubKeyIndex_ + offset ); return *this; }
    const_iterator & operator-=( difference_type const offset ) { goToIndex( currentSubKeyIndex_ - offset ); return *this; }

    const_iterator   operator+ ( difference_type const offset ) const { return const_iterator( parentKey_, currentSubKeyIndex_ + offset ); }
    const_iterator   operator- ( difference_type const offset ) const { return const_iterator( parentKey_, currentSubKeyIndex_ - offset ); }

    const_iterator & operator= ( const_iterator const & );

    value_type & operator* () const { assert( currentSubKeyName_.size() ); return currentSubKeyName_; }
    value_type * operator->() const { return &**this; }

    bool operator==( const_iterator const & other ) const { return currentSubKeyIndex_ == other.currentSubKeyIndex_ && parentKey_ == other.parentKey_; }
    bool operator!=( const_iterator const & other ) const { return !( *this == other ); }
    bool operator< ( const_iterator const & other ) const { assert( ( parentKey_ == other.parentKey_ ) && "Mismatched iterators" ); return currentSubKeyIndex_ < other.currentSubKeyIndex_; }

    // "Not exactly" standard conformant.
    const_iterator operator[]( difference_type const offset ) const { return *this + offset; }

public: // Utility interface.
    distance_type currentIndex() const { return currentSubKeyIndex_; }
    HKEY const &  parentKey   () const { return parentKey_; }
    void          reset       ()       { goToIndex( 0 ); }

private:
    void goToIndex( unsigned int keyIndex );

private:
    HKEY          parentKey_         ;
    distance_type currentSubKeyIndex_;
    WinString     currentSubKeyName_ ;  // Not using value_type to enable the assignment operator.
    // (todo) think of a better solution that will not "explode" under Unicode.
    TCHAR         nameBuffer_[ RegistryKey::maximumRegistryKeyNameLength ];
};

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