Home Software Systems Services Buy Now Articles About
Hundreds Lines of Code
Audio Control ver. 4 show menu the most ergonomic volume control utility
   
 

If you ever wondered what such a program looks like, or just what could be inside of Audio Control version 4, than you might want to have a look in the body of a function that I have included bellow. This code is written in a programming language called "C++" and is only one of hundreds of functions that I wrote for Audio Control to become reality. These functions rely on many more functions and services provided by the operating system. Besides C++ there are many other programming languages having different positive and negative features. The most powerful feature of C++ is the high level of abstraction that it offers.

If you are software development professional you might note the use of memory atoms in the body of the function. Although in this function memory is just barely used, meaning that it does not demonstrate at all the actual power of the Atomic Memory Model you still could notice the ease of handling of the memory. All necessary checks during allocation, use (overrun tests), and release of the memory as well as its actual release are strictly and rigorously made however their presence is hidden, thus not additionally obstructing the already complicated code.

Have fun! ;)

void CDestinationLineEntries::SortMixers( const MList< Pair< const MixerSortCriteria, bool > >& caSortOrder, const bool bLogicalOnly ) throw()
{
// Read the Use Data from the storage if necessary.
if( AudioMixerControl::mscUse == caSortOrder.GetHead()->GetLabelRef() )
{
listMixersUseData.Empty();
 
// Retrieve use data from storage and build the appropriate data structure with it.
HKEY hkRoot( NULL );
 
if( ERROR_SUCCESS == RegCreateKeyEx( HKEY_CURRENT_USER,
((CAudioControlApp*)AfxGetApp())->GetAppRelativePath(),
0,
TEXT(""),
REG_OPTION_NON_VOLATILE,
KEY_QUERY_VALUE, NULL,
&hkRoot,
NULL ) )
{
DWORD dwValueSize( 0 );
 
if( ERROR_SUCCESS != RegQueryValueEx( hkRoot,
AUDIO_DEVICE_FIRST_CONTROL_USE_DATA_STORAGE_NAME,
NULL,
NULL,
NULL,
&dwValueSize ) )
{
dwValueSize = 0;
}
 
MMemoryPH< BYTE, HEAP_ZERO_MEMORY > memUseData( MMemory< BYTE >::MemUnits( (DWORD)dwValueSize ) );
 
if( ERROR_SUCCESS == RegQueryValueEx( hkRoot,
AUDIO_DEVICE_FIRST_CONTROL_USE_DATA_STORAGE_NAME,
NULL,
NULL,
(BYTE*)(memUseData.GetMemory()),
&dwValueSize ) )
{
// Distribute the data.
const BYTE* pb1Data( memUseData );
BYTE const* pb1FirstBefindData( pb1Data + memUseData.GetSizeBytes() );
 
while( pb1Data < pb1FirstBefindData )
{
Pair< DWORD, USHORT >::AddToHashTable( Pair< DWORD, USHORT >( *(DWORD*)pb1Data, *(USHORT*)(pb1Data + sizeof( DWORD )) ),
listMixersUseData,
true );
 
pb1Data += sizeof( DWORD ) + sizeof( USHORT );
}
}
 
RegCloseKey( hkRoot );
}
 
listMixersUseData.Accelerate();
}
 
 
// First separate the mixers in two flows - privileged (always on top) and normal.
MList< Pair< CAdjustMixer*, MList< CAdjustMixer* > > > listFlowPriviliged;
MList< Pair< CAdjustMixer*, MList< CAdjustMixer* > > > listFlowNormal;
 
for( DWORD dwMixer = 0; dwMixer < listMajorDependents.GetMembersCount(); dwMixer++ )
{
if( (DWORD)MList< CAdjustMixer* >::Invalid == listListControlNeighbours.Find_H2T( listMajorDependents[dwMixer]->GetLabelRef() ) )
{
// Add to the flow of normal groups.
MASSERT( AudioMixerControl::Major == listMajorDependents[dwMixer]->GetLabelRef()->GetMixerItem()->GetImportance() );
 
listFlowNormal.AddTail( listMajorDependents[dwMixer] );
}
else
{
// Add to the flow of privileged groups.
MASSERT( AudioMixerControl::Major == listMajorDependents[dwMixer]->GetLabelRef()->GetMixerItem()->GetImportance() );
 
listFlowPriviliged.AddTail( listMajorDependents[dwMixer] );
}
}
 
listMajorDependents.EmptyNoDelete();
 
 
// Sort each flow of groups and the controls within each group and merge the two flows.
 
const CAdjustMixer::Comparator< const CAdjustMixer* > tcComparator( caSortOrder );
 
// Transfer the groups in correct order from the privileged flow to the destination list.
while( !listFlowPriviliged.IsEmpty() )
{
listFlowPriviliged.Accelerate();
 
DWORD dwExtremum( 0 );
 
for( dwMixer = dwExtremum + 1; dwMixer < listFlowPriviliged.GetMembersCount(); dwMixer++ )
{
if( !tcComparator.IsOrdered( listFlowPriviliged[dwExtremum]->GetLabelRef(), listFlowPriviliged[dwMixer]->GetLabelRef() ) )
{
dwExtremum = dwMixer;
}
}
 
// The dwExtremum is the indef of the following group to be added to the sorted list.
listMajorDependents.AddTail( listFlowPriviliged.RemoveMember( dwExtremum ) );
 
// The insignificant group is not sorted, so sort it now.
listMajorDependents.GetTail()->GetValueRef().SortList< CAdjustMixer::Comparator< const CAdjustMixer* > >( tcComparator );
listMajorDependents.GetTail()->GetValueRef().Accelerate();
}
 
 
// Transfer the groups in correct order from the normal flow to the destination list.
while( !listFlowNormal.IsEmpty() )
{
listFlowNormal.Accelerate();
 
DWORD dwExtremum( 0 );
 
for( dwMixer = dwExtremum + 1; dwMixer < listFlowNormal.GetMembersCount(); dwMixer++ )
{
if( !tcComparator.IsOrdered( listFlowNormal[dwExtremum]->GetLabelRef(), listFlowNormal[dwMixer]->GetLabelRef() ) )
{
dwExtremum = dwMixer;
}
}
 
// The dwExtremum is the indef of the following group to be added to the sorted list.
listMajorDependents.AddTail( listFlowNormal.RemoveMember( dwExtremum ) );
 
// The insignificant group is not sorted, so sort it now.
listMajorDependents.GetTail()->GetValueRef().SortList< CAdjustMixer::Comparator< const CAdjustMixer* > >( tcComparator );
listMajorDependents.GetTail()->GetValueRef().Accelerate();
}
 
listMajorDependents.Accelerate();
 
// Finally build the "display" list.
listMixersSortedPtr.Empty();
 
for( dwMixer = 0; dwMixer < listMajorDependents.GetMembersCount(); dwMixer++ )
{
listMixersSortedPtr.AddTail( new CAdjustMixer*( listMajorDependents[dwMixer]->GetLabelRef() ) );
 
MList< CAdjustMixer* >& listGroupMembers( listMajorDependents[dwMixer]->GetValueRef() );
 
for( DWORD dwGroupMember = 0; dwGroupMember < listGroupMembers.GetMembersCount(); dwGroupMember++ )
{
listMixersSortedPtr.AddTail( new CAdjustMixer*( *listGroupMembers[dwGroupMember] ) );
}
}
 
listMixersSortedPtr.Accelerate();
 
 
// Rearrangement of the CAdjustMixer in the system Z order, so the tab order will be
// consistent with the view order.
CWnd* pwndLastZOrder( this );
 
for( DWORD dwMixer = 0; dwMixer < listMixersSortedPtr.GetMembersCount(); dwMixer++ )
{
MASSERT( IsWindow( pwndLastZOrder->m_hWnd ) );
 
(*listMixersSortedPtr[dwMixer])->SetWindowPos( pwndLastZOrder,
0,
0,
0,
0,
SWP_NOACTIVATE |
SWP_NOCOPYBITS |
SWP_NOMOVE |
SWP_NOREDRAW |
SWP_NOSIZE |
SWP_NOOWNERZORDER );
 
pwndLastZOrder = (*listMixersSortedPtr[dwMixer]);
}
 
 
// To use listMixersSortedPtr - it must be sorted first - confirmation.
MASSERT( listMixersSortedPtr.GetMembersCount() == listMixers.GetMembersCount() );
 
if( !bLogicalOnly )
{
// Redispaly the CAdjustMixers in accordance with the new order.
SCROLLINFO si;
ZeroMemory( &si, sizeof( SCROLLINFO ) );
si.cbSize = sizeof( SCROLLINFO );
 
GetScrollInfo( SB_VERT, &si, SIF_POS | SIF_PAGE | SIF_RANGE);
 
MASSERT( int( min( si.nMax - si.nPage + Scroll_Min, (DWORD)max( Scroll_Min, si.nPos ) ) ) == si.nPos );
 
CRect rcMixer;
(*listMixersSortedPtr[0])->GetWindowRect( rcMixer );
ScreenToClient( rcMixer );
 
// si.nPos is correct for the scroll, but the scroll has offset from the display as the display
// always starts from ( 0, 0 ) client coordinates, so it needs to shift si.nPos with scroll_min.
rcMixer.top = - (si.nPos - Scroll_Min);
 
for( DWORD dwMixer = 0; dwMixer < listMixersSortedPtr.GetMembersCount(); dwMixer++ )
{
if( !(*listMixersSortedPtr[dwMixer])->IsWindowVisible() ) { continue; }
 
rcMixer.bottom = rcMixer.top + uiScrollLine;
 
(*listMixersSortedPtr[dwMixer])->MoveWindow( rcMixer, FALSE );
 
rcMixer.top = rcMixer.bottom;
}
 
RedrawWindow();
}
}
 
   
© Copyright 2011 by Miroslav Bonchev Bonchev. All Rights Reserved. Disclaimer Privacy Antispam email this page
email this page
To:
use semicolon to separate emails eg: [email protected]; [email protected]
Subject:
Message:
a link to this page will be automatically added to your message
From: