memspy/Engine/Source/ThreadAndProcess/MemSpyEngineObjectThreadInfoObjects.cpp
changeset 0 a03f92240627
child 20 a71a3e32a2ae
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/memspy/Engine/Source/ThreadAndProcess/MemSpyEngineObjectThreadInfoObjects.cpp	Tue Feb 02 01:57:15 2010 +0200
@@ -0,0 +1,3421 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). 
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+#include <memspy/engine/memspyengineobjectthreadinfoobjects.h>
+
+// System includes
+#include <f32file.h>
+#include <hal.h>
+#include <kernel/arm/arm_types.h>
+#include <memspy/driver/memspydriverclient.h>
+#include <memspy/engine/memspyengine.h>
+#include <memspy/engine/memspyengineutils.h>
+#include <memspy/engine/memspyengineoutputlist.h>
+#include <memspy/engine/memspyenginehelpercodesegment.h>
+#include <memspy/engine/memspyenginehelperactiveobject.h>
+#include <memspy/engine/memspyenginehelperchunk.h>
+#include <memspy/engine/memspyenginehelperheap.h>
+#include <memspy/engine/memspyenginehelperprocess.h>
+#include <memspy/engine/memspyengineobjectprocess.h>
+#include <memspy/engine/memspyengineobjectthread.h>
+#include <memspy/engine/memspyengineobjectthreadinfocontainer.h>
+#include <memspy/engine/memspyengineoutputsink.h>
+
+// User includes
+#include "MemSpyEngineOutputListItem.h"
+
+// Constants
+const TInt KMemSpyNumericFormatBufferSize = 20;
+
+// Literal constants
+_LIT( KMemSpyNumericHexFormat, "0x%08x" );
+_LIT( KMemSpyNumericDecFormat, "%d" );
+_LIT( KMemSpyNumericLongFormat, "%Ld" );
+_LIT( KMemSpyCaptionYes, "Yes" );
+_LIT( KMemSpyCaptionNo, "No" );
+_LIT( KMemSpyCaptionOn, "On" );
+_LIT( KMemSpyCaptionOff, "Off" );
+_LIT( KMemSpyUnavailable, "Unavailable" );
+_LIT( KMemSpyDead, "Dead" );
+_LIT( KMemSpyNoItems, "(No items)" );
+
+
+
+CMemSpyThreadInfoItemBase::CMemSpyThreadInfoItemBase( CMemSpyThreadInfoContainer& aContainer, TMemSpyThreadInfoItemType aType, TBool aAsyncConstruction )
+:   CMemSpyEngineObject( aContainer ), iContainer( aContainer ), iCallBack( CActive::EPriorityLow ), iType( aType )
+    {
+    if  ( aAsyncConstruction )
+        {
+        TCallBack callBackMethod( CallConstructL, this );
+        iCallBack.Set( callBackMethod );
+        iCallBack.CallBack();
+        }
+    }
+
+
+CMemSpyThreadInfoItemBase::~CMemSpyThreadInfoItemBase()
+    {
+    TRAP_IGNORE( iContainer.NotifyObserverL( MMemSpyThreadInfoContainerObserver::EInfoItemDestroyed, iType ) );
+    //
+    iItems.ResetAndDestroy();
+    iItems.Close();
+    }
+
+
+TInt CMemSpyThreadInfoItemBase::CallConstructL( TAny* aSelf )
+    {
+    CMemSpyThreadInfoItemBase* self = reinterpret_cast< CMemSpyThreadInfoItemBase* >( aSelf );
+    self->iReady = EFalse;
+    
+    // Don't try to refresh dead thread
+    TInt err = KErrNone;
+    if ( !self->Container().Thread().IsDead() )
+        {
+        TRAP(err, self->ConstructL());
+        if  ( err != KErrNone )
+            {
+    #ifdef _DEBUG
+            RDebug::Printf( "CMemSpyThreadInfoItemBase::CallConstructL() - construction err: %d, iType: %d", err, self->iType );
+    #endif
+            self->AddItemL( KMemSpyUnavailable, KNullDesC );
+            self->iIsEmpty = ETrue;
+            }
+        else if ( self->MdcaCount() == 0 )
+            {
+            self->AddItemL( KMemSpyNoItems, KNullDesC );
+            self->iIsEmpty = ETrue;
+            }        
+        }
+    else
+        {
+        self->AddItemL( KMemSpyDead, KNullDesC );
+        self->iIsEmpty = ETrue;
+        }
+    //
+    self->iReady = ETrue;
+    return KErrNone;
+    }
+
+
+EXPORT_C TInt CMemSpyThreadInfoItemBase::MdcaCount() const
+    {
+    return iItems.Count();
+    }
+
+
+EXPORT_C TPtrC CMemSpyThreadInfoItemBase::MdcaPoint( TInt aIndex ) const
+    {
+    CItem* item = iItems[ aIndex ];
+    return TPtrC( item->Combined() );
+    }
+
+
+EXPORT_C CMemSpyEngine& CMemSpyThreadInfoItemBase::Engine() const
+    {
+    return iContainer.Engine();
+    }
+
+
+EXPORT_C void CMemSpyThreadInfoItemBase::PrintL()
+    {
+    const TInt count = iItems.Count();
+    if  ( count > 0 && !iIsEmpty )
+        {
+        CMemSpyEngine& engine = Engine();
+        CMemSpyEngineOutputSink& sink = engine.Sink();
+
+        HBufC* name = MemSpyEngineUtils::CleanupTextLC( Name() );
+        sink.OutputSectionHeadingL( *name, TChar('-') );
+        CleanupStack::PopAndDestroy( name );
+        sink.OutputPrefixSetLC( _L("  ") ); // Slight insertion
+
+        // First pass to get max lengths
+        TInt maxLengthCaption = 0;
+        TInt maxLengthValue = 0;
+
+        for( TInt j=0; j<count; j++ )
+            {
+            const CItem* item = iItems[ j ];
+            maxLengthCaption = Max( maxLengthCaption, item->Caption().Length() );
+            maxLengthValue = Max( maxLengthValue, item->Value().Length() );
+            }
+
+        // Second pass - real this time - to print the values
+        HBufC* line = HBufC::NewLC( ( maxLengthCaption + maxLengthValue ) + 20 );
+        TPtr pLine( line->Des() );
+        //
+        for( TInt i=0; i<count; i++ )
+            {
+            const CItem* item = iItems[ i ];
+
+            // Remove initial tabs in caption
+            HBufC* caption = MemSpyEngineUtils::CleanupTextLC( item->Caption() );
+        
+            // Create value item & replace any further tabs
+            HBufC* value = MemSpyEngineUtils::CleanupTextLC( item->Value() );
+
+            // Now format the final line, with padding.
+            pLine.Justify( *caption, maxLengthCaption + 3, ELeft, TChar(' ') );
+            pLine.Append( *value );
+            CleanupStack::PopAndDestroy( 2, caption );
+
+            // Sink output
+            sink.OutputLineL( pLine );
+            }
+        //
+        CleanupStack::PopAndDestroy( line );
+        sink.OutputBlankLineL();
+        CleanupStack::PopAndDestroy(); // clear prefix
+        }
+    }
+
+
+
+void CMemSpyThreadInfoItemBase::AddItemL( const TDesC& aCaption, const TDesC& aValue )
+    {
+    CItem* item = CItem::NewLC( aCaption, aValue );
+    iItems.AppendL( item );
+    CleanupStack::Pop( item );
+    }
+
+
+void CMemSpyThreadInfoItemBase::AddItemHexL( const TDesC& aCaption, TUint aValue )
+    {
+    TBuf<KMemSpyNumericFormatBufferSize> val;
+    val.Format( KMemSpyNumericHexFormat, aValue );
+    AddItemL( aCaption, val );
+    }
+
+
+void CMemSpyThreadInfoItemBase::AddItemDecimalL( const TDesC& aCaption, TInt aValue )
+    {
+    TBuf<KMemSpyNumericFormatBufferSize> val;
+    val.Format( KMemSpyNumericDecFormat, aValue );
+    AddItemL( aCaption, val );
+    }
+
+
+void CMemSpyThreadInfoItemBase::AddItemLongL( const TDesC& aCaption, const TInt64& aValue )
+    {
+    TBuf<KMemSpyNumericFormatBufferSize> val;
+    val.Format( KMemSpyNumericLongFormat, aValue );
+    AddItemL( aCaption, val );
+    }
+
+
+void CMemSpyThreadInfoItemBase::AddItemYesNoL( const TDesC& aCaption, TBool aYes )
+    {
+    CItem* item = CItem::NewYesNoLC( aCaption, aYes );
+    iItems.AppendL( item );
+    CleanupStack::Pop( item );
+    }
+
+
+void CMemSpyThreadInfoItemBase::AddItemOnOffL( const TDesC& aCaption, TBool aOn )
+    {
+    CItem* item = CItem::NewOnOffLC( aCaption, aOn );
+    iItems.AppendL( item );
+    CleanupStack::Pop( item );
+    }
+
+
+void CMemSpyThreadInfoItemBase::AddItemPercentageL( const TDesC& aCaption, TInt aOneHundredPercentValue, TInt aValue )
+    {
+    const TMemSpyPercentText val( MemSpyEngineUtils::FormatPercentage( TReal( aOneHundredPercentValue ), TReal( aValue ) ) );
+    AddItemL( aCaption, val );
+    }
+
+
+EXPORT_C void CMemSpyThreadInfoItemBase::RebuildL()
+    {
+    Reset();
+    CallConstructL( this );
+    }
+
+
+EXPORT_C TBool CMemSpyThreadInfoItemBase::IsReady() const
+    {
+    return iReady;
+    }
+
+
+EXPORT_C TMemSpyThreadInfoItemType CMemSpyThreadInfoItemBase::Type() const
+    {
+    return iType;
+    }
+
+
+void CMemSpyThreadInfoItemBase::Reset()
+    {
+    iItems.ResetAndDestroy();
+    }
+
+
+void CMemSpyThreadInfoItemBase::StripProcessAndThreadNames( TDes& aText )
+    {
+    StripProcessName( aText );
+    StripThreadName( aText );
+    }
+
+
+void CMemSpyThreadInfoItemBase::StripProcessName( TDes& aText )
+    {
+    CMemSpyProcess& process = Container().Thread().Process();
+    const TPtrC processName( process.Name() );
+    TFullName temp;
+    //
+    _LIT( KProcessNameUidFormat1, "%S.exe[%08x]" );
+    temp.Format( KProcessNameUidFormat1, &processName, process.SID() );
+    const TBool stripped = MemSpyEngineUtils::StripText( aText, temp );
+    //
+    if  ( stripped == EFalse )
+        {
+        _LIT( KProcessNameUidFormat2, "%S[%08x]" );
+        temp.Format( KProcessNameUidFormat2, &processName, process.SID() );
+        MemSpyEngineUtils::StripText( aText, temp );
+        }
+    }
+
+
+void CMemSpyThreadInfoItemBase::StripThreadName( TDes& aText )
+    {
+    CMemSpyThread& thread = Container().Thread();
+    const TPtrC threadName( thread.Name() );
+    const TBool stripped = MemSpyEngineUtils::StripText( aText, threadName );
+    (void) stripped;
+    }
+
+
+CMemSpyThreadInfoItemBase::CItem& CMemSpyThreadInfoItemBase::Item( TInt aIndex )
+    {
+    CItem* item = iItems[ aIndex ];
+    return *item;
+    }
+
+
+const CMemSpyThreadInfoItemBase::CItem& CMemSpyThreadInfoItemBase::Item( TInt aIndex ) const
+    {
+    const CItem* item = iItems[ aIndex ];
+    return *item;
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoItemBase::CItem::CItem()
+    {
+    }
+
+
+CMemSpyThreadInfoItemBase::CItem::~CItem()
+    {
+    delete iCaption;
+    delete iValue;
+    delete iCombined;
+    }
+
+
+void CMemSpyThreadInfoItemBase::CItem::ConstructL( const TDesC& aCaption, const TDesC& aValue )
+    {
+    iCaption = aCaption.AllocL();
+    iValue = aValue.AllocL();
+    //
+    UpdateCombinedL();
+    }
+
+
+CMemSpyThreadInfoItemBase::CItem* CMemSpyThreadInfoItemBase::CItem::NewLC( const CItem& aCopyMe )
+    {
+    CItem* self = new(ELeave) CItem();
+    CleanupStack::PushL( self );
+    self->ConstructL( aCopyMe.Caption(), aCopyMe.Value() );
+    return self;
+    }
+
+
+CMemSpyThreadInfoItemBase::CItem* CMemSpyThreadInfoItemBase::CItem::NewLC( const TDesC& aCaption )
+    {
+    CItem* self = new(ELeave) CItem();
+    CleanupStack::PushL( self );
+    self->ConstructL( aCaption, KNullDesC );
+    return self;
+    }
+
+
+CMemSpyThreadInfoItemBase::CItem* CMemSpyThreadInfoItemBase::CItem::NewLC( const TDesC& aCaption, const TDesC& aValue )
+    {
+    CItem* self = new(ELeave) CItem();
+    CleanupStack::PushL( self );
+    self->ConstructL( aCaption, aValue );
+    return self;
+    }
+
+
+CMemSpyThreadInfoItemBase::CItem* CMemSpyThreadInfoItemBase::CItem::NewHexLC( const TDesC& aCaption, TUint aValue )
+    {
+    CItem* ret = CItem::NewLC( aCaption );
+    ret->SetHexL( aValue );
+    return ret;
+    }
+
+
+CMemSpyThreadInfoItemBase::CItem* CMemSpyThreadInfoItemBase::CItem::NewDecimalLC( const TDesC& aCaption, TInt aValue )
+    {
+    CItem* ret = CItem::NewLC( aCaption );
+    ret->SetDecimalL( aValue );
+    return ret;
+    }
+
+
+CMemSpyThreadInfoItemBase::CItem* CMemSpyThreadInfoItemBase::CItem::NewLongLC( const TDesC& aCaption, const TInt64& aValue )
+    {
+    CItem* ret = CItem::NewLC( aCaption );
+    ret->SetLongL( aValue );
+    return ret;
+    }
+
+
+CMemSpyThreadInfoItemBase::CItem* CMemSpyThreadInfoItemBase::CItem::NewYesNoLC( const TDesC& aCaption, TBool aYes )
+    {
+    CItem* ret = CItem::NewLC( aCaption );
+    ret->SetYesNoL( aYes );
+    return ret;
+    }
+
+
+CMemSpyThreadInfoItemBase::CItem* CMemSpyThreadInfoItemBase::CItem::NewOnOffLC( const TDesC& aCaption, TBool aOn )
+    {
+    CItem* ret = CItem::NewLC( aCaption );
+    ret->SetOnOffL( aOn );
+    return ret;
+    }
+
+
+CMemSpyThreadInfoItemBase::CItem* CMemSpyThreadInfoItemBase::CItem::NewPercentageLC( const TDesC& aCaption, TInt aOneHundredPercentValue, TInt aValue )
+    {
+    CItem* ret = CItem::NewLC( aCaption );
+    ret->SetPercentageL( aOneHundredPercentValue, aValue );
+    return ret;
+    }
+
+
+void CMemSpyThreadInfoItemBase::CItem::SetValueL( const TDesC& aValue )
+    {
+    if  ( iValue == NULL )
+        {
+        iValue = aValue.AllocL();
+        }
+    else
+        {
+        if  ( iValue->Des().MaxLength() < aValue.Length() )
+            {
+            iValue = iValue->ReAllocL( aValue.Length() );
+            }
+            
+        // Now its safe to assign new content
+        *iValue = aValue;
+        }
+        
+    UpdateCombinedL();
+    }
+
+
+void CMemSpyThreadInfoItemBase::CItem::SetHexL( TUint aValue )
+    {
+    TBuf<KMemSpyNumericFormatBufferSize> val;
+    val.Format( KMemSpyNumericHexFormat, aValue );
+    SetValueL( val );
+    }
+
+
+void CMemSpyThreadInfoItemBase::CItem::SetDecimalL( TInt aValue )
+    {
+    TBuf<KMemSpyNumericFormatBufferSize> val;
+    val.Format( KMemSpyNumericDecFormat, aValue );
+    SetValueL( val );
+    }
+
+
+void CMemSpyThreadInfoItemBase::CItem::SetLongL( const TInt64& aValue )
+    {
+    TBuf<KMemSpyNumericFormatBufferSize> val;
+    val.Format( KMemSpyNumericLongFormat, aValue );
+    SetValueL( val );
+    }
+
+
+void CMemSpyThreadInfoItemBase::CItem::SetYesNoL( TBool aYes )
+    {
+    if  ( aYes )
+        {
+        SetValueL( KMemSpyCaptionYes );
+        }
+    else
+        {
+        SetValueL( KMemSpyCaptionNo );
+        }
+    }
+
+
+void CMemSpyThreadInfoItemBase::CItem::SetOnOffL( TBool aOn )
+    {
+    if  ( aOn )
+        {
+        SetValueL( KMemSpyCaptionOn );
+        }
+    else
+        {
+        SetValueL( KMemSpyCaptionOff );
+        }
+    }
+
+
+void CMemSpyThreadInfoItemBase::CItem::SetPercentageL( TInt aOneHundredPercentValue, TInt aValue )
+    {
+    const TMemSpyPercentText val( MemSpyEngineUtils::FormatPercentage( TReal( aOneHundredPercentValue ), TReal( aValue ) ) );
+    SetValueL( val );
+    }
+
+
+void CMemSpyThreadInfoItemBase::CItem::UpdateCombinedL()
+    {
+    const TInt requiredLength = Caption().Length() + Value().Length() + 10;
+    //
+    if  ( iCombined == NULL )
+        {
+        iCombined = HBufC::NewL( requiredLength );
+        }
+    else if ( iCombined->Des().MaxLength() < requiredLength )
+        {
+        iCombined = iCombined->ReAllocL( requiredLength );
+        }
+        
+    TPtr pCombined( iCombined->Des() );
+    pCombined.Zero();
+    pCombined.Append( _L("\t") );
+    pCombined.Append( Caption() );
+    pCombined.Append( _L("\t\t") );
+    pCombined.Append( Value() );
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoGeneral::CMemSpyThreadInfoGeneral( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+:   CMemSpyThreadInfoItemBase( aContainer, EMemSpyThreadInfoItemTypeGeneralInfo, aAsyncConstruction )
+    {
+    }
+
+
+void CMemSpyThreadInfoGeneral::ConstructL()
+    {
+    TBuf<50> temp;
+    RThread thread;
+    Container().Thread().OpenLC( thread );
+    const CMemSpyProcess& process = Container().Thread().Process();
+
+    _LIT( KItem1, "Thread Id" );
+    AddItemLongL( KItem1, thread.Id() );
+
+    _LIT( KItem1a, "Process Id" );
+    AddItemLongL( KItem1a, (TUint) process.Id() );
+  
+    _LIT( KItem1b, "SID" );
+    AddItemHexL( KItem1b, process.SID() );
+  
+    _LIT( KItem1c, "VID" );
+    AddItemHexL( KItem1c, process.VID() );
+
+    _LIT( KItem2, "Thread Priority" );
+    CMemSpyThread::AppendPriority( temp, thread.Priority() );
+    AddItemL( KItem2, temp );
+    temp.Zero();
+   
+    _LIT( KItem3, "Process Priority" );
+    CMemSpyProcess::AppendPriority( temp, thread.ProcessPriority() );
+    AddItemL( KItem3, temp );
+    temp.Zero();
+   
+    _LIT( KItem4, "Request Count" );
+    AddItemDecimalL( KItem4, thread.RequestCount() );
+   
+    TInt processHandleCount = 0;
+    TInt threadHandleCount = 0;
+    thread.HandleCount( processHandleCount, threadHandleCount );
+
+    _LIT( KItem5a, "Process Handles" );
+    AddItemDecimalL( KItem5a, processHandleCount );
+
+    _LIT( KItem5b, "Thread Handles" );
+    AddItemDecimalL( KItem5b, threadHandleCount );
+
+    // Thread handle info
+    THandleInfo handleInfo;
+    thread.HandleInfo( &handleInfo );
+
+    _LIT( KItem5c, "Num. Proc. (Using)" );
+    AddItemDecimalL( KItem5c, handleInfo.iNumProcesses );
+
+    _LIT( KItem5d, "Num. Thread (Using)" );
+    AddItemDecimalL( KItem5d, handleInfo.iNumThreads );
+
+    _LIT( KItem5e, "Attributes" );
+    AddItemDecimalL( KItem5e, thread.Attributes() );
+    
+    // CPU time (request special kernel build)
+    TTimeIntervalMicroSeconds cpuTime;
+    if  ( thread.GetCpuTime( cpuTime ) == KErrNone )
+        {
+        _LIT( KItem5f, "CPU Time (us)" );
+        const TInt64 time = cpuTime.Int64();
+        AddItemLongL( KItem5f, time );
+        }
+
+    // Exit info
+    _LIT( KItem6, "Exit Type" );
+    CMemSpyThread::AppendExitType( temp, thread.ExitType() );
+    AddItemL( KItem6, temp );
+    temp.Zero();
+
+    if  ( thread.ExitType() != EExitPending )
+        {
+        _LIT( KItem7, "Exit Reason" );
+        AddItemDecimalL( KItem7, thread.ExitReason() );
+
+        _LIT( KItem8, "Exit Category" );
+        const TExitCategoryName cat( thread.ExitCategory() );
+        AddItemL( KItem8, cat );
+        }
+
+    // Registers
+    MakeRegisterListingL( thread );
+    
+    CleanupStack::PopAndDestroy( &thread );
+
+    Container().NotifyObserverL( MMemSpyThreadInfoContainerObserver::EInfoItemChanged, Type() );
+    }
+
+
+CMemSpyThreadInfoGeneral* CMemSpyThreadInfoGeneral::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+    {
+    CMemSpyThreadInfoGeneral* self = new(ELeave) CMemSpyThreadInfoGeneral( aContainer, aAsyncConstruction );
+    CleanupStack::PushL( self );
+    if  ( !aAsyncConstruction )
+        {
+        self->ConstructL();
+        }
+    return self;
+    }
+
+
+EXPORT_C TPtrC CMemSpyThreadInfoGeneral::Name() const
+    {
+    _LIT(KName, "\tGeneral");
+    return TPtrC( KName );
+    }
+
+
+void CMemSpyThreadInfoGeneral::MakeRegisterListingL( RThread& aThread )
+    {
+#ifndef __WINS__
+    _LIT(KRegFormatGeneral, "R%02d");
+    _LIT(KRegFormatSP, "SP");
+    _LIT(KRegFormatLR, "LR");
+    _LIT(KRegFormatPC, "PC");
+    _LIT(KRegFormatFlags, "Flags");
+    _LIT(KRegFormatDACR, "DACR"); // Data access control register
+    //
+    TArmRegSet regList;
+    TPckg<TArmRegSet> pRegList( regList );
+    //
+    aThread.Context( pRegList );
+	TArmReg* pReg = reinterpret_cast<TArmReg*>( &regList );
+    //
+    for( TInt i=0; i<KArmRegisterCount; i++ )
+        {
+        const TArmReg regValue = pReg[ i ];
+        //
+        if  ( i <= EArmR12 )
+            {
+            TBuf<128> buf;
+            buf.Format( KRegFormatGeneral, i );
+            AddItemHexL( buf, regValue );
+            }
+        else
+            {
+            TPtrC pCaption( KRegFormatGeneral );
+            //
+            if  ( i == EArmSp )
+                {
+                pCaption.Set( KRegFormatSP );
+                }
+            else if ( i == EArmLr )
+                {
+                pCaption.Set( KRegFormatLR );
+                }
+            else if ( i == EArmPc )
+                {
+                pCaption.Set( KRegFormatPC );
+                }
+            else if ( i == EArmFlags )
+                {
+                pCaption.Set( KRegFormatFlags );
+                }
+            else if ( i == EArmDacr )
+                {
+                pCaption.Set( KRegFormatDACR );
+                }
+            //
+            AddItemHexL( pCaption, regValue );
+            }
+        }
+#else
+    (void) aThread;
+#endif
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoHeap::CMemSpyThreadInfoHeap( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+:   CMemSpyThreadInfoItemBase( aContainer, EMemSpyThreadInfoItemTypeHeap, aAsyncConstruction )
+    {
+    }
+
+
+void CMemSpyThreadInfoHeap::ConstructL()
+    {
+    CMemSpyEngineHelperHeap& heapHelper = Engine().HelperHeap();
+
+    // Get heap info first of all
+    TMemSpyHeapInfo info;
+    heapHelper.GetHeapInfoUserL( Container().Thread().Process().Id(), Container().Thread().Id(), info );
+    CMemSpyEngineOutputList* list = heapHelper.NewHeapSummaryShortLC( info );
+
+    // Now add each item to our view
+    const TInt count = list->Count();
+    for( TInt i=0; i<count; i++ )
+        {
+        const CMemSpyEngineOutputListItem& item = list->Item( i );
+        //
+        AddItemL( item.Caption(), item.Value() );
+        }
+
+    // Tidy up
+    CleanupStack::PopAndDestroy( list );
+    Container().NotifyObserverL( MMemSpyThreadInfoContainerObserver::EInfoItemChanged, Type() );
+    }
+
+
+CMemSpyThreadInfoHeap* CMemSpyThreadInfoHeap::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+    {
+    CMemSpyThreadInfoHeap* self = new(ELeave) CMemSpyThreadInfoHeap( aContainer, aAsyncConstruction );
+    CleanupStack::PushL( self );
+    if  ( !aAsyncConstruction )
+        {
+        self->ConstructL();
+        }
+    return self;
+    }
+
+
+EXPORT_C TPtrC CMemSpyThreadInfoHeap::Name() const
+    {
+    _LIT(KName, "\tHeap");
+    return TPtrC( KName );
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoActiveObjects::CMemSpyThreadInfoActiveObjects( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+:   CMemSpyThreadInfoItemBase( aContainer, EMemSpyThreadInfoItemTypeActiveObject, aAsyncConstruction )
+    {
+    }
+
+
+CMemSpyThreadInfoActiveObjects::~CMemSpyThreadInfoActiveObjects()
+    {
+    delete iItems;
+    }
+
+
+void CMemSpyThreadInfoActiveObjects::ConstructL()
+    {
+    CMemSpyEngine& engine = Container().Thread().Process().Engine();
+    engine.ProcessSuspendLC( Container().Thread().Process().Id() );
+    //
+    CMemSpyEngineActiveObjectArray* activeObjects = engine.HelperActiveObject().ActiveObjectListL( Container().Thread() );
+    delete iItems;
+    iItems = activeObjects;
+    //
+    CleanupStack::PopAndDestroy(); // ProcessSuspendLC
+
+    Container().NotifyObserverL( MMemSpyThreadInfoContainerObserver::EInfoItemChanged, Type() );
+    }
+
+
+CMemSpyThreadInfoActiveObjects* CMemSpyThreadInfoActiveObjects::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+    {
+    CMemSpyThreadInfoActiveObjects* self = new(ELeave) CMemSpyThreadInfoActiveObjects( aContainer, aAsyncConstruction );
+    CleanupStack::PushL( self );
+    if  ( !aAsyncConstruction )
+        {
+        self->ConstructL();
+        }
+    return self;
+    }
+
+
+EXPORT_C TPtrC CMemSpyThreadInfoActiveObjects::Name() const
+    {
+    _LIT(KName, "\tActive Objects");
+    return TPtrC( KName );
+    }
+
+
+EXPORT_C TInt CMemSpyThreadInfoActiveObjects::MdcaCount() const
+    {
+    TInt count = 0;
+    //
+    if  ( iItems )
+        {
+        count = iItems->MdcaCount();
+        }
+    //
+    return count;
+    }
+
+
+EXPORT_C TPtrC CMemSpyThreadInfoActiveObjects::MdcaPoint(TInt aIndex) const
+    {
+    TPtrC ret( KNullDesC );
+    //
+    if  ( iItems )
+        {
+        ret.Set( iItems->MdcaPoint( aIndex ) );
+        }
+    //
+    return ret;
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoOpenFiles::CMemSpyThreadInfoOpenFiles( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+:   CMemSpyThreadInfoItemBase( aContainer, EMemSpyThreadInfoItemTypeOpenFiles, aAsyncConstruction )
+    {
+    }
+
+
+void CMemSpyThreadInfoOpenFiles::ConstructL()
+    {
+    _LIT(KSpace, " ");
+    //
+    const TThreadId myThreadId = Container().Thread().Id();
+    CMemSpyEngine& engine = Container().Thread().Process().Engine();
+    RFs& fsSession = engine.FsSession();
+    //
+    TMemSpySizeText valueBuf;
+    TBuf<128> timeBuf;
+    TOpenFileScan scanner( fsSession );
+    //
+    CFileList* list = NULL;
+    scanner.NextL( list );
+
+    while( list != NULL )
+        {
+        if  ( scanner.ThreadId() == myThreadId )
+            {
+            CleanupStack::PushL( list );
+    
+            const TInt entryCount = list->Count();
+            for(TInt i=0; i<entryCount; i++)
+                {
+                const TEntry& entry = (*list)[ i ];
+
+                // Get time and size format strings
+                valueBuf = MemSpyEngineUtils::FormatSizeText( entry.iSize );
+                MemSpyEngineUtils::FormatTimeL( timeBuf, entry.iModified );
+                timeBuf.Insert( 0, KSpace );
+                timeBuf.Insert( 0, valueBuf );
+
+                // Get just file name
+                TParsePtrC parser( entry.iName );
+                const TPtrC pJustName( parser.NameAndExt() );
+
+                // Create item 
+                AddItemL( pJustName, timeBuf );
+                }
+
+            CleanupStack::Pop( list );
+            }
+
+        delete list;
+        list = NULL;
+        scanner.NextL( list );
+        }
+
+    Container().NotifyObserverL( MMemSpyThreadInfoContainerObserver::EInfoItemChanged, Type() );
+    }
+
+
+CMemSpyThreadInfoOpenFiles* CMemSpyThreadInfoOpenFiles::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+    {
+    CMemSpyThreadInfoOpenFiles* self = new(ELeave) CMemSpyThreadInfoOpenFiles( aContainer, aAsyncConstruction );
+    CleanupStack::PushL( self );
+    if  ( !aAsyncConstruction )
+        {
+        self->ConstructL();
+        }
+    return self;
+    }
+
+
+EXPORT_C TPtrC CMemSpyThreadInfoOpenFiles::Name() const
+    {
+    _LIT(KName, "\tOpen Files");
+    return TPtrC( KName );
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoStack::CMemSpyThreadInfoStack( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+:   CMemSpyThreadInfoItemBase( aContainer, EMemSpyThreadInfoItemTypeStack, aAsyncConstruction )
+    {
+    }
+
+
+void CMemSpyThreadInfoStack::ConstructL()
+    {
+    CMemSpyEngine& engine = Container().Thread().Process().Engine();
+    engine.ProcessSuspendLC( Container().Thread().Process().Id() );
+    //
+    TMemSpyDriverStackInfo info;
+    const TInt error = engine.Driver().GetStackInfo( Container().Thread().Id(), info );
+    User::LeaveIfError( error );
+    
+    _LIT( KItem1, "Size" );
+    AddItemDecimalL( KItem1, info.iUserStackSize );
+
+#ifndef __WINS__
+    const TInt userStackUsage = (TInt) ( info.iUserStackBase + info.iUserStackSize ) - info.iUserStackPointer;
+    const TInt userStackHighWaterMarkUsage = (TInt) ( info.iUserStackBase + info.iUserStackSize ) - info.iUserStackHighWatermark;
+
+    _LIT( KItem2, "Stack used" );
+    AddItemDecimalL( KItem2, userStackUsage );
+    
+    _LIT( KItem3, "(percentage)" );
+    AddItemPercentageL( KItem3, info.iUserStackSize, userStackUsage );
+
+    _LIT( KItem4, "High watermark" );
+    AddItemDecimalL( KItem4, userStackHighWaterMarkUsage );
+    
+    _LIT( KItem5, "(percentage)" );
+    AddItemPercentageL( KItem5, info.iUserStackSize, userStackHighWaterMarkUsage );
+#endif
+
+    _LIT( KItem6, "Base address" );
+    AddItemHexL( KItem6, info.iUserStackBase );
+
+#ifndef __WINS__
+    _LIT( KItem7, "Current pointer" );
+    AddItemHexL( KItem7, info.iUserStackPointer );
+#endif
+    //
+    CleanupStack::PopAndDestroy(); // ProcessSuspendLC
+
+    Container().NotifyObserverL( MMemSpyThreadInfoContainerObserver::EInfoItemChanged, Type() );
+    }
+
+
+CMemSpyThreadInfoStack* CMemSpyThreadInfoStack::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+    {
+    CMemSpyThreadInfoStack* self = new(ELeave) CMemSpyThreadInfoStack( aContainer, aAsyncConstruction );
+    CleanupStack::PushL( self );
+    if  ( !aAsyncConstruction )
+        {
+        self->ConstructL();
+        }
+    return self;
+    }
+
+
+EXPORT_C TPtrC CMemSpyThreadInfoStack::Name() const
+    {
+    _LIT(KName, "\tStack");
+    return TPtrC( KName );
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoChunk::CMemSpyThreadInfoChunk( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+:   CMemSpyThreadInfoItemBase( aContainer, EMemSpyThreadInfoItemTypeChunk, aAsyncConstruction )
+    {
+    }
+
+
+CMemSpyThreadInfoChunk::~CMemSpyThreadInfoChunk()
+    {
+    delete iList;
+    }
+
+
+void CMemSpyThreadInfoChunk::ConstructL()
+    {
+    CMemSpyEngine& engine = Container().Thread().Process().Engine();
+    engine.ProcessSuspendLC( Container().Thread().Process().Id() );
+    //
+    CMemSpyEngineChunkList* list = engine.HelperChunk().ListForThreadL( Container().Thread().Id() );
+    delete iList;
+    iList = list;
+    //
+    CleanupStack::PopAndDestroy(); // ProcessSuspendLC
+
+    Container().NotifyObserverL( MMemSpyThreadInfoContainerObserver::EInfoItemChanged, Type() );
+    }
+
+
+CMemSpyThreadInfoChunk* CMemSpyThreadInfoChunk::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+    {
+    CMemSpyThreadInfoChunk* self = new(ELeave) CMemSpyThreadInfoChunk( aContainer, aAsyncConstruction );
+    CleanupStack::PushL( self );
+    if  ( !aAsyncConstruction )
+        {
+        self->ConstructL();
+        }
+    return self;
+    }
+
+
+EXPORT_C TPtrC CMemSpyThreadInfoChunk::Name() const
+    {
+    _LIT(KName, "\tChunks");
+    return TPtrC( KName );
+    }
+
+
+EXPORT_C TInt CMemSpyThreadInfoChunk::MdcaCount() const
+    {
+    TInt count = 0;
+    //
+    if  ( iList )
+        {
+        count = iList->MdcaCount();
+        }
+    //
+    return count;
+    }
+
+
+EXPORT_C TPtrC CMemSpyThreadInfoChunk::MdcaPoint(TInt aIndex) const
+    {
+    TPtrC ret( KNullDesC );
+    //
+    if  ( iList )
+        {
+        ret.Set( iList->MdcaPoint( aIndex ) );
+        }
+    //
+    return ret;
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoCodeSeg::CMemSpyThreadInfoCodeSeg( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+:   CMemSpyThreadInfoItemBase( aContainer, EMemSpyThreadInfoItemTypeCodeSeg, aAsyncConstruction )
+    {
+    }
+
+
+CMemSpyThreadInfoCodeSeg::~CMemSpyThreadInfoCodeSeg()
+    {
+    delete iList;
+    }
+
+
+void CMemSpyThreadInfoCodeSeg::ConstructL()
+    {
+    CMemSpyEngine& engine = Container().Thread().Process().Engine();
+    engine.ProcessSuspendLC( Container().Thread().Process().Id() );
+    //
+    CMemSpyEngineCodeSegList* list = engine.HelperCodeSegment().CodeSegmentListL( Container().Thread().Process().Id() );
+    delete iList;
+    iList = list;
+    //
+    CleanupStack::PopAndDestroy(); // ProcessSuspendLC
+
+    Container().NotifyObserverL( MMemSpyThreadInfoContainerObserver::EInfoItemChanged, Type() );
+    }
+
+
+CMemSpyThreadInfoCodeSeg* CMemSpyThreadInfoCodeSeg::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+    {
+    CMemSpyThreadInfoCodeSeg* self = new(ELeave) CMemSpyThreadInfoCodeSeg( aContainer, aAsyncConstruction );
+    CleanupStack::PushL( self );
+    if  ( !aAsyncConstruction )
+        {
+        self->ConstructL();
+        }
+    return self;
+    }
+
+
+EXPORT_C TPtrC CMemSpyThreadInfoCodeSeg::Name() const
+    {
+    _LIT(KName, "\tCode Segments");
+    return TPtrC( KName );
+    }
+
+
+EXPORT_C TInt CMemSpyThreadInfoCodeSeg::MdcaCount() const
+    {
+    TInt count = 0;
+    //
+    if  ( iList )
+        {
+        count = iList->MdcaCount();
+        }
+    //
+    return count;
+    }
+
+
+EXPORT_C TPtrC CMemSpyThreadInfoCodeSeg::MdcaPoint(TInt aIndex) const
+    {
+    TPtrC ret( KNullDesC );
+    //
+    if  ( iList )
+        {
+        ret.Set( iList->MdcaPoint( aIndex ) );
+        }
+    //
+    return ret;
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoHandleObjectBase::CMemSpyThreadInfoHandleObjectBase( CMemSpyThreadInfoContainer& aContainer, TMemSpyThreadInfoItemType aItemType, TMemSpyDriverContainerType aContainerType, TBool aAsyncConstruction )
+:   CMemSpyThreadInfoItemBase( aContainer, aItemType, aAsyncConstruction ), iContainerType( aContainerType )
+    {
+    }
+
+
+CMemSpyThreadInfoHandleObjectBase::~CMemSpyThreadInfoHandleObjectBase()
+    {
+#ifdef _DEBUG
+    RDebug::Printf( "CMemSpyThreadInfoHandleObjectBase::~CMemSpyThreadInfoHandleObjectBase() - this: 0x%08x", this );
+#endif
+    iInfoItems.Close();
+    }
+
+
+void CMemSpyThreadInfoHandleObjectBase::ConstructL()
+    {
+#ifdef _DEBUG
+    RDebug::Printf( "CMemSpyThreadInfoHandleObjectBase::ConstructL() - START" );
+#endif
+    iInfoItems.Reset();
+    //
+    CMemSpyProcess& process = Container().Thread().Process();
+    CMemSpyEngine& engine = process.Engine();
+    engine.ProcessSuspendLC( process.Id() );
+    //
+    RArray<THandleWrapper> handles;
+    CleanupClosePushL( handles );
+    GetHandlesL( handles );
+#ifdef _DEBUG
+    RDebug::Printf( "CMemSpyThreadInfoHandleObjectBase::ConstructL() - got %d handle entries...", handles.Count() );
+#endif
+    //
+    TFullName name;
+    TMemSpyDriverHandleInfoGeneric info;
+    //
+    const TInt count = handles.Count();
+    for (TInt i=0; i<count; i++)
+    	{
+    	const THandleWrapper& handleWrapper = handles[ i ];
+        //
+    	const TInt r = engine.Driver().GetGenericHandleInfo( Container().Thread().Id(), handleWrapper.iType, handleWrapper.iHandle, info );
+        //
+#ifdef _DEBUG
+        RDebug::Printf( "CMemSpyThreadInfoHandleObjectBase::ConstructL() - handle[%3d] 0x%08x, type: %d, refCount: %d, r: %d", i, handleWrapper.iHandle, handleWrapper.iType, handleWrapper.iRefCount, r );
+#endif
+        //
+        if  (r == KErrNone)
+    		{
+            name.Copy( info.iName );
+#ifdef _DEBUG
+            RDebug::Print( _L( "CMemSpyThreadInfoHandleObjectBase::ConstructL() - HANDLE [%3d] %S"), handleWrapper.iRefCount, &name );
+#endif
+            StripProcessAndThreadNames( name );
+            //
+            iInfoItems.AppendL( info );
+            HandleContainerItemL( info, handleWrapper.iRefCount, name );
+            }
+     	}
+
+    CleanupStack::PopAndDestroy( &handles );
+    CleanupStack::PopAndDestroy(); // ProcessSuspendLC
+
+    HandleAllItemsLocatedL();
+
+    Container().NotifyObserverL( MMemSpyThreadInfoContainerObserver::EInfoItemChanged, Type() );
+    }
+
+
+TBool CMemSpyThreadInfoHandleObjectBase::THandleWrapper::Match( const THandleWrapper& aLeft, const THandleWrapper& aRight )
+    {
+    return ( aLeft.iHandle == aRight.iHandle );
+    }
+
+
+EXPORT_C TInt CMemSpyThreadInfoHandleObjectBase::DetailsIndexByEntry( const TMemSpyDriverHandleInfoGeneric& aEntry ) const
+    {
+#ifdef _DEBUG
+    RDebug::Printf( "CMemSpyThreadInfoHandleObjectBase::DetailsIndexByEntry() - START - this: 0x%08x, aEntry.iHandle: 0x%08x", this, aEntry.iHandle );
+#endif
+    //
+    const TInt ret = DetailsIndexByHandle( aEntry.iHandle );
+    //
+#ifdef _DEBUG
+    RDebug::Printf( "CMemSpyThreadInfoHandleObjectBase::DetailsIndexByEntry() - END - ret: %d", ret );
+#endif
+    return ret;
+    }
+
+
+EXPORT_C TInt CMemSpyThreadInfoHandleObjectBase::DetailsIndexByHandle( TAny* aHandle ) const
+    {
+#ifdef _DEBUG
+    RDebug::Printf( "CMemSpyThreadInfoHandleObjectBase::DetailsIndexByHandle() - START - this: 0x%08x, aHandle: 0x%08x", this, aHandle );
+#endif
+    TInt ret = KErrNotFound;
+    //
+    const TInt count = DetailsCount();
+    for(TInt i=0; i<count; i++)
+        {
+        const TMemSpyDriverHandleInfoGeneric& item = DetailsAt( i );
+        if  ( item.iHandle == aHandle )
+            {
+            ret = i;
+            break;
+            }
+        }
+    //
+#ifdef _DEBUG
+    RDebug::Printf( "CMemSpyThreadInfoHandleObjectBase::DetailsIndexByHandle() - END - ret: %d", ret );
+#endif
+    return ret;
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoHandleByContainer::CMemSpyThreadInfoHandleByContainer( CMemSpyThreadInfoContainer& aContainer, TMemSpyThreadInfoItemType aItemType, TMemSpyDriverContainerType aContainerType, TBool aAsyncConstruction )
+:   CMemSpyThreadInfoHandleObjectBase( aContainer, aItemType, aContainerType, aAsyncConstruction )
+    {
+    }
+
+
+void CMemSpyThreadInfoHandleByContainer::GetHandlesL( RArray<THandleWrapper>& aArray )
+    {
+#ifdef _DEBUG
+    RDebug::Printf( "CMemSpyThreadInfoHandleByContainer::GetHandlesL() - START - container: %d", ContainerType() );
+#endif
+
+    aArray.Reset();
+
+    // Our handles will be stored here... duplicates are filtered out
+    TInt r = KErrNone;
+	TInt c = KMemSpyDefaultMaxHandleCount;
+	TAny* handles[ KMemSpyDefaultMaxHandleCount ];
+
+    CMemSpyProcess& process = Container().Thread().Process();
+    CMemSpyEngine& engine = process.Engine();
+    TIdentityRelation<CMemSpyThreadInfoHandleObjectBase::THandleWrapper> finder( THandleWrapper::Match );
+
+    // First get the handles for the process
+    if  ( r == KErrNone )
+        {
+        c = KMemSpyDefaultMaxHandleCount;
+        r = engine.Driver().GetProcessHandlesByType( process.Id(), ContainerType(), handles, c );
+        if  ( r == KErrNone && c > 0 )
+    	    {
+            c = Min( c, KMemSpyDefaultMaxHandleCount );
+    	    for( TInt i=0; i<c; i++ )
+    		    {
+    		    TAny* handle = handles[ i ];
+
+                // Create temporary entry that we'll use as the key in our array...
+                CMemSpyThreadInfoHandleObjectBase::THandleWrapper entry( handle, ContainerType() );
+                
+                // Find existing duplicate entry (if there is one...)
+                const TInt errorOrIndex = aArray.Find( entry, finder );
+#ifdef _DEBUG
+                RDebug::Printf( "CMemSpyThreadInfoHandleByContainer::GetHandlesL() - PROC[%03d/%03d] - handle: 0x%08x, foundIndex: %d", i+1, c, handle, errorOrIndex );
+#endif
+
+    		    if  ( errorOrIndex == KErrNotFound )
+        		    {
+        		    // Not a duplicate handle, so keep it
+        		    aArray.AppendL( entry );
+#ifdef _DEBUG
+                    RDebug::Printf( "      new entry: 0x%08x", handle );
+#endif
+        		    }
+                else if ( errorOrIndex >= 0 )
+                    {
+                    // Increment reference count for duplicates...
+                    CMemSpyThreadInfoHandleObjectBase::THandleWrapper& existingEntry = aArray[ errorOrIndex ];
+                    ++existingEntry.iRefCount;
+#ifdef _DEBUG
+                    RDebug::Printf( "      dupe entry - count is now: %d", existingEntry.iRefCount );
+#endif
+                    }
+     		    }
+            }
+        }
+
+    // Next get the handles for the thread
+    if  ( r == KErrNone )
+        {
+        c = KMemSpyDefaultMaxHandleCount;
+        r = engine.Driver().GetThreadHandlesByType( Container().Thread().Id(), ContainerType(), handles, c );
+        if  ( r == KErrNone && c > 0 )
+    	    {
+            c = Min( c, KMemSpyDefaultMaxHandleCount );
+    	    for( TInt i=0; i<c; i++ )
+    		    {
+    		    TAny* handle = handles[ i ];
+
+                // Create temporary entry that we'll use as the key in our array...
+                CMemSpyThreadInfoHandleObjectBase::THandleWrapper entry( handle, ContainerType() );
+                
+                // Find existing duplicate entry (if there is one...)
+                const TInt errorOrIndex = aArray.Find( entry, finder );
+#ifdef _DEBUG
+                RDebug::Printf(  "CMemSpyThreadInfoHandleByContainer::GetHandlesL() - THRD[%03d/%03d] - handle: 0x%08x, foundIndex: %d", i+1, c, handle, errorOrIndex );
+#endif
+    		    
+    		    if  ( errorOrIndex == KErrNotFound )
+        		    {
+        		    // Not a duplicate handle, so keep it
+        		    aArray.AppendL( entry );
+#ifdef _DEBUG
+                    RDebug::Printf( "      new entry: 0x%08x", handle );
+#endif
+        		    }
+                else if ( errorOrIndex >= 0 )
+                    {
+                    // Increment reference count for duplicates...
+                    CMemSpyThreadInfoHandleObjectBase::THandleWrapper& existingEntry = aArray[ errorOrIndex ];
+                    ++existingEntry.iRefCount;
+#ifdef _DEBUG
+                    RDebug::Printf( "      dupe entry - count is now: %d", existingEntry.iRefCount );
+#endif
+                    }
+     		    }
+            }
+        }
+
+#ifdef _DEBUG
+    RDebug::Printf(  "CMemSpyThreadInfoHandleByContainer::GetHandlesL() - final handle listing: " );
+
+    const TInt finalCount = aArray.Count();
+    for( TInt i=0; i<finalCount; i++ )
+        {
+        const THandleWrapper& handle = aArray[ i ];
+        RDebug::Printf(  "entry[%03d/%03d] - handle: 0x%08x, type: %d, refCount: %d", i+1, finalCount, handle.iHandle, handle.iType, handle.iRefCount );
+        }
+
+    RDebug::Printf( "CMemSpyThreadInfoHandleByContainer::GetHandlesL() - END - container: %d, finalCount: %d", ContainerType(), finalCount );
+#endif
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoServer::CMemSpyThreadInfoServer( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+:   CMemSpyThreadInfoHandleByContainer( aContainer, EMemSpyThreadInfoItemTypeServer, EMemSpyDriverContainerTypeServer, aAsyncConstruction )
+    {
+    }
+
+
+CMemSpyThreadInfoServer* CMemSpyThreadInfoServer::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+    {
+    CMemSpyThreadInfoServer* self = new(ELeave) CMemSpyThreadInfoServer( aContainer, aAsyncConstruction );
+    CleanupStack::PushL( self );
+    if  ( !aAsyncConstruction )
+        {
+        self->ConstructL();
+        }
+    return self;
+    }
+
+
+EXPORT_C TPtrC CMemSpyThreadInfoServer::Name() const
+    {
+    _LIT(KName, "\tServers Running in Thread");
+    return TPtrC( KName );
+    }
+
+
+void CMemSpyThreadInfoServer::HandleContainerItemL( TMemSpyDriverHandleInfoGeneric& /*aItem*/, TInt /*aRefCount*/, TDes& aFullName )
+    {
+    AddItemL( aFullName, KNullDesC );
+    }
+
+
+EXPORT_C TPtrC CMemSpyThreadInfoServer::SessionType( TIpcSessionType aType )
+    {
+    _LIT( KUnsharable, "Unsharable" );
+    _LIT( KSharable, "Sharable" );
+    _LIT( KGlobalSharable, "Global Sharable" );
+    //
+    TPtrC pType(KNullDesC);
+    switch( aType )
+        {
+    case EIpcSession_Unsharable:
+        pType.Set( KUnsharable );
+        break;
+    case EIpcSession_Sharable:
+        pType.Set( KSharable );
+        break;
+    case EIpcSession_GlobalSharable:
+        pType.Set( KGlobalSharable );
+        break;
+    default:
+        pType.Set( KMemSpyUnavailable );
+        break;
+        }
+    //
+    return pType;
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoSession::CMemSpyThreadInfoSession( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+:   CMemSpyThreadInfoHandleByContainer( aContainer, EMemSpyThreadInfoItemTypeSession, EMemSpyDriverContainerTypeSession, aAsyncConstruction )
+    {
+    }
+
+
+CMemSpyThreadInfoSession::~CMemSpyThreadInfoSession()
+    {
+    iServerNames.ResetAndDestroy();
+    iServerNames.Close();
+    }
+
+
+CMemSpyThreadInfoSession* CMemSpyThreadInfoSession::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+    {
+    CMemSpyThreadInfoSession* self = new(ELeave) CMemSpyThreadInfoSession( aContainer, aAsyncConstruction );
+    CleanupStack::PushL( self );
+    if  ( !aAsyncConstruction )
+        {
+        self->ConstructL();
+        }
+    return self;
+    }
+
+
+EXPORT_C TPtrC CMemSpyThreadInfoSession::Name() const
+    {
+    _LIT(KName, "\tClient <-> Server\nConnections");
+    return TPtrC( KName );
+    }
+
+
+void CMemSpyThreadInfoSession::Reset()
+    {
+    CMemSpyThreadInfoHandleByContainer::Reset();
+    iServerNames.ResetAndDestroy();
+    }
+
+
+EXPORT_C TInt CMemSpyThreadInfoSession::ConnectionCount( const TDesC& aName ) const
+    {
+    TInt ret = 0;
+
+#ifdef _DEBUG
+    RDebug::Print( _L("CMemSpyThreadInfoSession::ConnectionCount() - START - aName: %S"), &aName );
+#endif
+
+    // See if we have an entry with that name...
+    TIdentityRelation<CSessionInfoEntry> comparer( CompareEntries );
+    HBufC* name = aName.AllocLC();
+    CSessionInfoEntry* entry = new(ELeave) CSessionInfoEntry( name );
+    CleanupStack::Pop( name );
+    CleanupStack::PushL( entry );
+    const TInt foundIndex = iServerNames.Find( entry, comparer );
+    CleanupStack::PopAndDestroy( entry );
+    
+    // If we did, get the count
+    if  ( foundIndex >=0 && foundIndex < iServerNames.Count() )
+        {
+        ret = iServerNames[ foundIndex ]->iCount;
+        }
+    //
+#ifdef _DEBUG
+    RDebug::Printf( "CMemSpyThreadInfoSession::ConnectionCount() - END - ret: %d", ret );
+#endif
+    //
+    return ret;
+    }
+
+
+void CMemSpyThreadInfoSession::HandleContainerItemL( TMemSpyDriverHandleInfoGeneric& aItem, TInt /*aRefCount*/, TDes& aFullName )
+    {
+    // Check whether we have the item already?
+    TIdentityRelation<CSessionInfoEntry> comparer( CompareEntries );
+
+    // Prepare object, just in case we don't find it...
+    HBufC* name = aFullName.AllocLC();
+
+#ifdef _DEBUG
+    TBuf<KMaxName> origName; origName.Copy( aItem.iName );
+    RDebug::Print( _L("CMemSpyThreadInfoSession::HandleContainerItemL() - START - handle: 0x%08x, type: %d, origName: %S, modName: %S"), aItem.iHandle, aItem.iType, &origName, name );
+#else
+    (void) aItem;
+#endif
+
+    CSessionInfoEntry* entry = new(ELeave) CSessionInfoEntry( name );
+    CleanupStack::Pop( name );
+    CleanupStack::PushL( entry );
+
+    // Search
+    const TInt foundIndex = iServerNames.Find( entry, comparer );
+    if  ( foundIndex == KErrNotFound )
+        {
+        // Make new entry
+        iServerNames.AppendL( entry );
+        CleanupStack::Pop( entry );
+        }
+    else if ( foundIndex >= 0 )
+        {
+        // Existing entry, increment count
+        CleanupStack::PopAndDestroy( entry );
+        entry = iServerNames[ foundIndex ];
+        ++entry->iCount;
+        }
+    else
+        {
+        CleanupStack::PopAndDestroy( entry );
+        }
+ 
+#ifdef _DEBUG
+    RDebug::Printf( "CMemSpyThreadInfoSession::HandleContainerItemL() - END - foundIndex: %d", foundIndex );
+#endif
+    }
+
+
+void CMemSpyThreadInfoSession::HandleAllItemsLocatedL()
+    {
+    _LIT(KSecondLineFormatStringCount1, "1 connection");
+    _LIT(KSecondLineFormatStringCountMoreThanOne, "%d connections");
+    TBuf<50> buf;
+
+    // All items have been found, now create listbox entries
+    const TInt count = iServerNames.Count();
+    for( TInt i=0; i<count; i++ )
+        {
+        CSessionInfoEntry* entry = iServerNames[ i ];
+
+        if  ( entry->iCount == 1 )
+            {
+            buf.Copy( KSecondLineFormatStringCount1 );
+            }
+        else
+            {
+            buf.Format( KSecondLineFormatStringCountMoreThanOne, entry->iCount );
+            }
+
+        AddItemL( *entry->iName, buf );
+        }
+    }
+
+
+TBool CMemSpyThreadInfoSession::CompareEntries( const CSessionInfoEntry& aLeft, const CSessionInfoEntry& aRight )
+    {
+    return ( aLeft.iName->CompareF( *aRight.iName ) == 0 );
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoSemaphore::CMemSpyThreadInfoSemaphore( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+:   CMemSpyThreadInfoHandleByContainer( aContainer, EMemSpyThreadInfoItemTypeSemaphore, EMemSpyDriverContainerTypeSemaphore, aAsyncConstruction )
+    {
+    }
+
+
+CMemSpyThreadInfoSemaphore* CMemSpyThreadInfoSemaphore::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+    {
+    CMemSpyThreadInfoSemaphore* self = new(ELeave) CMemSpyThreadInfoSemaphore( aContainer, aAsyncConstruction );
+    CleanupStack::PushL( self );
+    if  ( !aAsyncConstruction )
+        {
+        self->ConstructL();
+        }
+    return self;
+    }
+
+
+EXPORT_C TPtrC CMemSpyThreadInfoSemaphore::Name() const
+    {
+    _LIT(KName, "\tSemaphores");
+    return TPtrC( KName );
+    }
+
+
+void CMemSpyThreadInfoSemaphore::HandleContainerItemL( TMemSpyDriverHandleInfoGeneric& aItem, TInt /*aRefCount*/, TDes& aFullName )
+    {
+    _LIT( KFormatSpec, "Count: %d" );
+    TBuf<50> buf;
+    buf.AppendFormat( KFormatSpec, aItem.iCount );
+
+    AddItemL( aFullName, buf );
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoMutex::CMemSpyThreadInfoMutex( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+:   CMemSpyThreadInfoHandleByContainer( aContainer, EMemSpyThreadInfoItemTypeMutex, EMemSpyDriverContainerTypeMutex, aAsyncConstruction )
+    {
+    }
+
+
+CMemSpyThreadInfoMutex* CMemSpyThreadInfoMutex::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+    {
+    CMemSpyThreadInfoMutex* self = new(ELeave) CMemSpyThreadInfoMutex( aContainer, aAsyncConstruction );
+    CleanupStack::PushL( self );
+    if  ( !aAsyncConstruction )
+        {
+        self->ConstructL();
+        }
+    return self;
+    }
+
+
+EXPORT_C TPtrC CMemSpyThreadInfoMutex::Name() const
+    {
+    _LIT(KName, "\tMutexes");
+    return TPtrC( KName );
+    }
+
+
+void CMemSpyThreadInfoMutex::HandleContainerItemL( TMemSpyDriverHandleInfoGeneric& aItem, TInt /*aRefCount*/, TDes& aFullName )
+    {
+    _LIT( KFormatSpec, "Count: %d" );
+    TBuf<50> buf;
+    buf.AppendFormat( KFormatSpec, aItem.iCount );
+
+    AddItemL( aFullName, buf );
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoTimer::CMemSpyThreadInfoTimer( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+:   CMemSpyThreadInfoHandleByContainer( aContainer, EMemSpyThreadInfoItemTypeTimer, EMemSpyDriverContainerTypeTimer, aAsyncConstruction )
+    {
+    }
+
+
+CMemSpyThreadInfoTimer* CMemSpyThreadInfoTimer::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+    {
+    CMemSpyThreadInfoTimer* self = new(ELeave) CMemSpyThreadInfoTimer( aContainer, aAsyncConstruction );
+    CleanupStack::PushL( self );
+    if  ( !aAsyncConstruction )
+        {
+        self->ConstructL();
+        }
+    return self;
+    }
+
+
+EXPORT_C TPtrC CMemSpyThreadInfoTimer::Name() const
+    {
+    _LIT(KName, "\tTimers");
+    return TPtrC( KName );
+    }
+
+
+void CMemSpyThreadInfoTimer::HandleContainerItemL( TMemSpyDriverHandleInfoGeneric& aItem, TInt /*aRefCount*/, TDes& /*aFullName*/ )
+    {
+    // Get useful strings
+    TBuf<20> state;
+    GetTimerState( aItem.iTimerState, state );
+    TBuf<20> type;
+    GetTimerType( aItem.iTimerType, type );
+
+    AddItemL( type, state );
+    }
+
+
+void CMemSpyThreadInfoTimer::GetTimerState( TMemSpyDriverTimerState aState, TDes& aBuf )
+    {
+    switch( aState )
+        {
+    default:
+    case EMemSpyDriverTimerStateUnknown: 
+        {
+        _LIT(KStateUnknown, "Unknown");
+        aBuf.Copy( KStateUnknown );
+        }
+        break;
+    case EMemSpyDriverTimerStateIdle:
+        {
+        _LIT(KStateIdle, "Idle");
+        aBuf.Copy( KStateIdle );
+        }
+        break;
+    case EMemSpyDriverTimerStateWaiting: 
+        {
+        _LIT(KStateWaiting, "Waiting");
+        aBuf.Copy( KStateWaiting );
+        }
+        break;
+    case EMemSpyDriverTimerStateWaitHighRes: 
+        {
+        _LIT(KStateWaitHighRes, "Waiting, High Res.");
+        aBuf.Copy( KStateWaitHighRes );
+        }
+        break;
+        }
+    }
+
+
+void CMemSpyThreadInfoTimer::GetTimerType( TMemSpyDriverTimerType aType, TDes& aBuf )
+    {
+    switch( aType )
+        {
+    case EMemSpyDriverTimerTypeRelative:
+        {
+        _LIT( KType, "Relative" );
+        aBuf.Copy( KType );
+        }
+        break;
+    case EMemSpyDriverTimerTypeAbsolute:
+        {
+        _LIT( KType, "Absolute" );
+        aBuf.Copy( KType );
+        }
+        break;
+    case EMemSpyDriverTimerTypeHighRes:
+        {
+        _LIT( KType, "High Res." );
+        aBuf.Copy( KType );
+        }
+        break;
+    case EMemSpyDriverTimerTypeInactivity:
+        {
+        _LIT( KType, "Inactivity" );
+        aBuf.Copy( KType );
+        }
+        break;
+    default:
+        {
+        _LIT( KType, "Unknown" );
+        aBuf.Copy( KType );
+        }
+        break;
+        }
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoLDD::CMemSpyThreadInfoLDD( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+:   CMemSpyThreadInfoHandleByContainer( aContainer, EMemSpyThreadInfoItemTypeLDD, EMemSpyDriverContainerTypeLogicalDevice, aAsyncConstruction )
+    {
+    }
+
+
+CMemSpyThreadInfoLDD* CMemSpyThreadInfoLDD::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+    {
+    CMemSpyThreadInfoLDD* self = new(ELeave) CMemSpyThreadInfoLDD( aContainer, aAsyncConstruction );
+    CleanupStack::PushL( self );
+    if  ( !aAsyncConstruction )
+        {
+        self->ConstructL();
+        }
+    return self;
+    }
+
+
+EXPORT_C TPtrC CMemSpyThreadInfoLDD::Name() const
+    {
+    _LIT(KName, "\tLogical Device Drivers");
+    return TPtrC( KName );
+    }
+
+
+void CMemSpyThreadInfoLDD::HandleContainerItemL( TMemSpyDriverHandleInfoGeneric& aItem, TInt /*aRefCount*/, TDes& aFullName )
+    {
+    _LIT( KFormatSpec, "Open channels: %d" );
+    TBuf<50> buf;
+    buf.AppendFormat( KFormatSpec, aItem.iOpenChannels );
+
+    AddItemL( aFullName, buf );
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoPDD::CMemSpyThreadInfoPDD( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+:   CMemSpyThreadInfoHandleByContainer( aContainer, EMemSpyThreadInfoItemTypePDD, EMemSpyDriverContainerTypePhysicalDevice, aAsyncConstruction )
+    {
+    }
+
+
+CMemSpyThreadInfoPDD* CMemSpyThreadInfoPDD::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+    {
+    CMemSpyThreadInfoPDD* self = new(ELeave) CMemSpyThreadInfoPDD( aContainer, aAsyncConstruction );
+    CleanupStack::PushL( self );
+    if  ( !aAsyncConstruction )
+        {
+        self->ConstructL();
+        }
+    return self;
+    }
+
+
+EXPORT_C TPtrC CMemSpyThreadInfoPDD::Name() const
+    {
+    _LIT(KName, "\tPhysical Device Drivers");
+    return TPtrC( KName );
+    }
+
+
+void CMemSpyThreadInfoPDD::HandleContainerItemL( TMemSpyDriverHandleInfoGeneric& /*aItem*/, TInt /*aRefCount*/, TDes& aFullName )
+    {
+    AddItemL( aFullName, KNullDesC );
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoLogicalChannel::CMemSpyThreadInfoLogicalChannel( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+:   CMemSpyThreadInfoHandleByContainer( aContainer, EMemSpyThreadInfoItemTypeLogicalChannel, EMemSpyDriverContainerTypeLogicalChannel, aAsyncConstruction )
+    {
+    }
+
+
+CMemSpyThreadInfoLogicalChannel* CMemSpyThreadInfoLogicalChannel::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+    {
+    CMemSpyThreadInfoLogicalChannel* self = new(ELeave) CMemSpyThreadInfoLogicalChannel( aContainer, aAsyncConstruction );
+    CleanupStack::PushL( self );
+    if  ( !aAsyncConstruction )
+        {
+        self->ConstructL();
+        }
+    return self;
+    }
+
+
+EXPORT_C TPtrC CMemSpyThreadInfoLogicalChannel::Name() const
+    {
+    _LIT(KName, "\tLogical DD Channels");
+    return TPtrC( KName );
+    }
+
+
+void CMemSpyThreadInfoLogicalChannel::HandleContainerItemL( TMemSpyDriverHandleInfoGeneric& /*aItem*/, TInt /*aRefCount*/, TDes& aFullName )
+    {
+    AddItemL( aFullName, KNullDesC );
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoChangeNotifier::CMemSpyThreadInfoChangeNotifier( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+:   CMemSpyThreadInfoHandleByContainer( aContainer, EMemSpyThreadInfoItemTypeChangeNotifier, EMemSpyDriverContainerTypeChangeNotifier, aAsyncConstruction )
+    {
+    }
+
+
+CMemSpyThreadInfoChangeNotifier* CMemSpyThreadInfoChangeNotifier::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+    {
+    CMemSpyThreadInfoChangeNotifier* self = new(ELeave) CMemSpyThreadInfoChangeNotifier( aContainer, aAsyncConstruction );
+    CleanupStack::PushL( self );
+    if  ( !aAsyncConstruction )
+        {
+        self->ConstructL();
+        }
+    return self;
+    }
+
+
+EXPORT_C TPtrC CMemSpyThreadInfoChangeNotifier::Name() const
+    {
+    _LIT(KName, "\tChange Notifiers");
+    return TPtrC( KName );
+    }
+
+
+void CMemSpyThreadInfoChangeNotifier::HandleContainerItemL( TMemSpyDriverHandleInfoGeneric& /*aItem*/, TInt /*aRefCount*/, TDes& aFullName )
+    {
+    AddItemL( aFullName, KNullDesC );
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoUndertaker::CMemSpyThreadInfoUndertaker( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+:   CMemSpyThreadInfoHandleByContainer( aContainer, EMemSpyThreadInfoItemTypeUndertaker, EMemSpyDriverContainerTypeUndertaker, aAsyncConstruction )
+    {
+    }
+
+
+CMemSpyThreadInfoUndertaker* CMemSpyThreadInfoUndertaker::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+    {
+    CMemSpyThreadInfoUndertaker* self = new(ELeave) CMemSpyThreadInfoUndertaker( aContainer, aAsyncConstruction );
+    CleanupStack::PushL( self );
+    if  ( !aAsyncConstruction )
+        {
+        self->ConstructL();
+        }
+    return self;
+    }
+
+
+EXPORT_C TPtrC CMemSpyThreadInfoUndertaker::Name() const
+    {
+    _LIT(KName, "\tUndertakers");
+    return TPtrC( KName );
+    }
+
+
+void CMemSpyThreadInfoUndertaker::HandleContainerItemL( TMemSpyDriverHandleInfoGeneric& /*aItem*/, TInt /*aRefCount*/, TDes& aFullName )
+    {
+    AddItemL( aFullName, KNullDesC );
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoOwnedThreadHandles::CMemSpyThreadInfoOwnedThreadHandles( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+:   CMemSpyThreadInfoHandleByContainer( aContainer, EMemSpyThreadInfoItemTypeOwnedThreadHandles, EMemSpyDriverContainerTypeThread, aAsyncConstruction )
+    {
+    }
+
+
+CMemSpyThreadInfoOwnedThreadHandles* CMemSpyThreadInfoOwnedThreadHandles::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+    {
+    CMemSpyThreadInfoOwnedThreadHandles* self = new(ELeave) CMemSpyThreadInfoOwnedThreadHandles( aContainer, aAsyncConstruction );
+    CleanupStack::PushL( self );
+    if  ( !aAsyncConstruction )
+        {
+        self->ConstructL();
+        }
+    return self;
+    }
+
+
+EXPORT_C TPtrC CMemSpyThreadInfoOwnedThreadHandles::Name() const
+    {
+    _LIT(KName, "\tHandles to other\nThreads");
+    return TPtrC( KName );
+    }
+
+
+void CMemSpyThreadInfoOwnedThreadHandles::HandleContainerItemL( TMemSpyDriverHandleInfoGeneric& aItem, TInt aRefCount, TDes& aFullName )
+    {
+    const TInt bracketPosStart = aFullName.LocateF( TChar('[') );
+    const TInt doubleColonPos = aFullName.FindF( _L("::" ) );
+    //
+    if  ( bracketPosStart >= 0 && doubleColonPos > bracketPosStart && doubleColonPos < aFullName.Length() - 2 )
+        {
+        // Process
+        TPtrC pProcessName( aFullName.Left( bracketPosStart ) );
+        HBufC* caption = HBufC::NewLC( KMaxName + 10 );
+        TPtr pCaption( caption->Des() );
+        pCaption.AppendFormat( _L("[%2d] %S"), aRefCount, &pProcessName );
+        
+        // Thread id & thread name
+        TPtrC pThreadName( aFullName.Mid( doubleColonPos + 2 ) );
+        HBufC* value = HBufC::NewLC( KMaxName + 10 );
+        TPtr pValue( value->Des() );
+        pValue.AppendFormat( _L("[%3d] %S"), aItem.iId, &pThreadName );
+
+        // Add it & tidy up
+        AddItemL( pCaption, pValue );
+        CleanupStack::PopAndDestroy( 2, caption );
+        }
+    else
+        {
+        AddItemL( aFullName, KNullDesC );
+        }
+    }
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoOwnedProcessHandles::CMemSpyThreadInfoOwnedProcessHandles( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+:   CMemSpyThreadInfoHandleByContainer( aContainer, EMemSpyThreadInfoItemTypeOwnedProcessHandles, EMemSpyDriverContainerTypeProcess, aAsyncConstruction )
+    {
+    }
+
+
+CMemSpyThreadInfoOwnedProcessHandles* CMemSpyThreadInfoOwnedProcessHandles::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+    {
+    CMemSpyThreadInfoOwnedProcessHandles* self = new(ELeave) CMemSpyThreadInfoOwnedProcessHandles( aContainer, aAsyncConstruction );
+    CleanupStack::PushL( self );
+    if  ( !aAsyncConstruction )
+        {
+        self->ConstructL();
+        }
+    return self;
+    }
+
+
+EXPORT_C TPtrC CMemSpyThreadInfoOwnedProcessHandles::Name() const
+    {
+    _LIT(KName, "\tHandles to other\nProcesses");
+    return TPtrC( KName );
+    }
+
+
+void CMemSpyThreadInfoOwnedProcessHandles::HandleContainerItemL( TMemSpyDriverHandleInfoGeneric& aItem, TInt aRefCount, TDes& aFullName )
+    {
+    const TInt bracketPosStart = aFullName.LocateF( TChar('[') );
+    const TInt doubleColonPos = aFullName.FindF( _L("::" ) );
+    //
+    if  ( bracketPosStart >= 0 && doubleColonPos > bracketPosStart && doubleColonPos < aFullName.Length() - 2 )
+        {
+        // Process
+        TPtrC pProcessName( aFullName.Left( bracketPosStart ) );
+        HBufC* caption = HBufC::NewLC( KMaxName + 10 );
+        TPtr pCaption( caption->Des() );
+        pCaption.AppendFormat( _L("[%2d] %S"), aRefCount, &pProcessName );
+        
+        // Thread id & thread name
+        TPtrC pThreadName( aFullName.Mid( doubleColonPos + 2 ) );
+        HBufC* value = HBufC::NewLC( KMaxName + 10 );
+        TPtr pValue( value->Des() );
+        pValue.AppendFormat( _L("[%3d] %S"), aItem.iId, &pThreadName );
+
+        // Add it & tidy up
+        AddItemL( pCaption, pValue );
+        CleanupStack::PopAndDestroy( 2, caption );
+        }
+    else
+        {
+        AddItemL( aFullName, KNullDesC );
+        }
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoReferencedBy::CMemSpyThreadInfoReferencedBy( CMemSpyThreadInfoContainer& aContainer, TMemSpyThreadInfoItemType aItemType, TMemSpyDriverContainerType aContainerType, TBool aAsyncConstruction )
+:   CMemSpyThreadInfoHandleObjectBase( aContainer, aItemType, aContainerType, aAsyncConstruction )
+    {
+    }
+
+
+void CMemSpyThreadInfoReferencedBy::GetHandlesL( RArray<THandleWrapper>& aArray )
+    {
+    aArray.Reset();
+    //
+    TInt r = KErrNone;
+    //
+    CMemSpyProcess& process = Container().Thread().Process();
+    CMemSpyEngine& engine = process.Engine();
+    TIdentityRelation<CMemSpyThreadInfoHandleObjectBase::THandleWrapper> finder( THandleWrapper::Match );
+
+    // We need to either search through:
+    //
+    // a) all thread & process handles looking for *this thread*, or
+    // b) all thread & process handles looking for *this process*
+    //
+    // We abuse the "container type" as a means of deciding whether it is
+    // the thread or the process we are looking for.
+    //
+    RMemSpyDriverClient& driver = engine.Driver();
+    if  ( ContainerType() == EMemSpyDriverContainerTypeProcess )
+        {
+        const TUint id = Container().Thread().Process().Id();
+        r = driver.GetReferencesToMyProcess( id );
+        }
+    else if ( ContainerType() == EMemSpyDriverContainerTypeThread )
+        {
+        const TUint id = Container().Thread().Id();
+        r = driver.GetReferencesToMyThread( id );
+        }
+    else
+        {
+        ASSERT( EFalse );
+        }
+    User::LeaveIfError( r );
+
+    RMemSpyMemStreamReader stream = driver.StreamOpenL();
+    CleanupClosePushL( stream );
+    
+    // Extract thread matches
+    const TInt threadCount = stream.ReadInt32L();
+    for( TInt i=0; i<threadCount; i++ )
+        {
+        TAny* handle = (TAny*) stream.ReadUint32L();
+
+        // Create temporary entry that we'll use as the key in our array...
+        CMemSpyThreadInfoHandleObjectBase::THandleWrapper entry( handle, EMemSpyDriverContainerTypeThread );
+        
+        // Find existing duplicate entry (if there is one...)
+        const TInt errorOrIndex = aArray.Find( entry, finder );
+	    
+	    if  ( errorOrIndex == KErrNotFound )
+		    {
+		    // Not a duplicate handle, so keep it
+		    aArray.AppendL( entry );
+		    }
+        else if ( errorOrIndex >= 0 )
+            {
+            // Increment reference count for duplicates...
+            CMemSpyThreadInfoHandleObjectBase::THandleWrapper& existingEntry = aArray[ errorOrIndex ];
+            ++existingEntry.iRefCount;
+            }
+        }
+    
+    // Extract process matches
+    const TInt processCount = stream.ReadInt32L();
+    for( TInt i=0; i<processCount; i++ )
+        {
+        TAny* handle = (TAny*) stream.ReadUint32L();
+
+        // Create temporary entry that we'll use as the key in our array...
+        CMemSpyThreadInfoHandleObjectBase::THandleWrapper entry( handle, EMemSpyDriverContainerTypeProcess );
+        
+        // Find existing duplicate entry (if there is one...)
+        const TInt errorOrIndex = aArray.Find( entry, finder );
+	    
+	    if  ( errorOrIndex == KErrNotFound )
+		    {
+		    // Not a duplicate handle, so keep it
+		    aArray.AppendL( entry );
+		    }
+        else if ( errorOrIndex >= 0 )
+            {
+            // Increment reference count for duplicates...
+            CMemSpyThreadInfoHandleObjectBase::THandleWrapper& existingEntry = aArray[ errorOrIndex ];
+            ++existingEntry.iRefCount;
+            }
+        }
+        
+    // Tidy up
+    CleanupStack::PopAndDestroy( &stream );
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoOtherThreads::CMemSpyThreadInfoOtherThreads( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+:   CMemSpyThreadInfoReferencedBy( aContainer, EMemSpyThreadInfoItemTypeOtherThreads, EMemSpyDriverContainerTypeThread, aAsyncConstruction )
+    {
+    }
+
+
+CMemSpyThreadInfoOtherThreads* CMemSpyThreadInfoOtherThreads::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+    {
+    CMemSpyThreadInfoOtherThreads* self = new(ELeave) CMemSpyThreadInfoOtherThreads( aContainer, aAsyncConstruction );
+    CleanupStack::PushL( self );
+    if  ( !aAsyncConstruction )
+        {
+        self->ConstructL();
+        }
+    return self;
+    }
+
+
+EXPORT_C TPtrC CMemSpyThreadInfoOtherThreads::Name() const
+    {
+    _LIT(KName, "\tReferences this Thread");
+    return TPtrC( KName );
+    }
+
+
+void CMemSpyThreadInfoOtherThreads::HandleContainerItemL( TMemSpyDriverHandleInfoGeneric& /*aItem*/, TInt /*aRefCount*/, TDes& aFullName )
+    {
+    AddItemL( aFullName, KNullDesC );
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoOtherProcesses::CMemSpyThreadInfoOtherProcesses( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+:   CMemSpyThreadInfoReferencedBy( aContainer, EMemSpyThreadInfoItemTypeOtherProcesses, EMemSpyDriverContainerTypeProcess, aAsyncConstruction )
+    {
+    }
+
+
+CMemSpyThreadInfoOtherProcesses* CMemSpyThreadInfoOtherProcesses::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+    {
+    CMemSpyThreadInfoOtherProcesses* self = new(ELeave) CMemSpyThreadInfoOtherProcesses( aContainer, aAsyncConstruction );
+    CleanupStack::PushL( self );
+    if  ( !aAsyncConstruction )
+        {
+        self->ConstructL();
+        }
+    return self;
+    }
+
+
+EXPORT_C TPtrC CMemSpyThreadInfoOtherProcesses::Name() const
+    {
+    _LIT(KName, "\tReferences this Process");
+    return TPtrC( KName );
+    }
+
+
+void CMemSpyThreadInfoOtherProcesses::HandleContainerItemL( TMemSpyDriverHandleInfoGeneric& /*aItem*/, TInt /*aRefCount*/, TDes& aFullName )
+    {
+    AddItemL( aFullName, KNullDesC );
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoMemoryTracking::CMemSpyThreadInfoMemoryTracking( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+:   CMemSpyThreadInfoItemBase( aContainer, EMemSpyThreadInfoItemTypeMemoryTracking, aAsyncConstruction ), iTotalIncludesSharedMemory( ETrue )
+    {
+    }
+
+
+CMemSpyThreadInfoMemoryTracking::~CMemSpyThreadInfoMemoryTracking()
+    {
+#ifdef _DEBUG
+    RDebug::Printf( "CMemSpyThreadInfoMemoryTracking::~CMemSpyThreadInfoMemoryTracking() - START - this: 0x%08x, iTracker: 0x%08x", this, iTracker );
+#endif
+    //
+    TrackingObserverRemove( *this );
+    //
+    delete iInfoHWM;
+    delete iInfoPeak;
+    delete iInfoCurrent;
+    //
+#ifdef _DEBUG
+    RDebug::Printf( "CMemSpyThreadInfoMemoryTracking::~CMemSpyThreadInfoMemoryTracking() - END - this: 0x%08x, iTracker: 0x%08x", this, iTracker );
+#endif
+    }
+
+
+void CMemSpyThreadInfoMemoryTracking::ConstructL()
+    {
+#ifdef _DEBUG
+    RDebug::Printf( "CMemSpyThreadInfoMemoryTracking::ConstructL() - START - this: 0x%08x, iTracker: 0x%08x", this, iTracker );
+#endif
+    CMemSpyEngine& engine = Container().Thread().Process().Engine();
+    //
+    const TProcessId pid = Container().Thread().Process().Id();
+    iTracker = engine.HelperProcess().TrackerOrNull( pid );
+
+#ifdef _DEBUG
+    RDebug::Printf( "CMemSpyThreadInfoMemoryTracking::ConstructL() - requesting observer add... - this: 0x%08x, iTracker: 0x%08x", this, iTracker );
+#endif
+    TrackingObserverAddL( *this );
+    //
+#ifdef _DEBUG
+    RDebug::Printf( "CMemSpyThreadInfoMemoryTracking::ConstructL() - preparing info item... - this: 0x%08x, iTracker: 0x%08x", this, iTracker );
+#endif
+    if  ( iTracker )
+        {
+        delete iInfoCurrent;
+        iInfoCurrent = NULL;
+        iInfoCurrent = CMemSpyThreadInfoMemoryTrackingStatisticsCurrent::NewLC( Container(), EFalse );
+        CleanupStack::Pop( iInfoCurrent );
+        //
+        delete iInfoHWM;
+        iInfoHWM = NULL;
+        iInfoHWM = CMemSpyThreadInfoMemoryTrackingStatisticsHWM::NewLC( Container(), EFalse );
+        CleanupStack::Pop( iInfoHWM );
+        //
+        delete iInfoPeak;
+        iInfoPeak = NULL;
+        iInfoPeak = CMemSpyThreadInfoMemoryTrackingStatisticsPeak::NewLC( Container(), EFalse );
+        CleanupStack::Pop( iInfoPeak );
+        }
+    
+#ifdef _DEBUG
+    RDebug::Printf( "CMemSpyThreadInfoMemoryTracking::ConstructL() - prepared info items - this: 0x%08x, iTracker: 0x%08x", this, iTracker );
+#endif
+
+    // Prepare items
+    _LIT( KItem0, "Tracking" );
+    AddItemOnOffL( KItem0, ( iTracker ) ? iTracker->AmTracking() : EFalse );
+
+    TInt64 valCurrent( 0 );
+    if  ( iTracker )
+        {
+        if  ( TotalIncludesSharedMemory() )
+            {
+            valCurrent = iTracker->InfoCurrent().TotalIncShared();
+            }
+        else
+            {
+            valCurrent = iTracker->InfoCurrent().TotalExcShared();
+            }
+        }
+    _LIT( KItem1, "Total [Current]" );
+    AddItemLongL( KItem1, valCurrent );
+
+    TInt64 valHWM( 0 );
+    if  ( iTracker )
+        {
+        if  ( TotalIncludesSharedMemory() )
+            {
+            valHWM = iTracker->InfoHWMIncShared().TotalIncShared();
+            }
+        else
+            {
+            valHWM = iTracker->InfoHWMExcShared().TotalExcShared();
+            }
+        }
+    _LIT( KItem2, "Total [HWM]" );
+    AddItemLongL( KItem2, valHWM );
+
+    TInt64 valPeak( 0 );
+    if  ( iTracker )
+        {
+        if  ( TotalIncludesSharedMemory() )
+            {
+            valPeak = iTracker->InfoPeaks().TotalIncShared();
+            }
+        else
+            {
+            valPeak = iTracker->InfoPeaks().TotalExcShared();
+            }
+        }
+    _LIT( KItem3, "Total [Peaks]" );
+    AddItemLongL( KItem3, valPeak );
+
+    //
+    Container().NotifyObserverL( MMemSpyThreadInfoContainerObserver::EInfoItemChanged, Type() );
+#ifdef _DEBUG
+    RDebug::Printf( "CMemSpyThreadInfoMemoryTracking::ConstructL() - END - this: 0x%08x", this );
+#endif
+    }
+
+
+CMemSpyThreadInfoMemoryTracking* CMemSpyThreadInfoMemoryTracking::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+    {
+    CMemSpyThreadInfoMemoryTracking* self = new(ELeave) CMemSpyThreadInfoMemoryTracking( aContainer, aAsyncConstruction );
+    CleanupStack::PushL( self );
+    if  ( !aAsyncConstruction )
+        {
+        self->ConstructL();
+        }
+    return self;
+    }
+
+
+EXPORT_C TPtrC CMemSpyThreadInfoMemoryTracking::Name() const
+    {
+    _LIT(KName, "\tMemory Tracking");
+    return TPtrC( KName );
+    }
+
+
+EXPORT_C TBool CMemSpyThreadInfoMemoryTracking::TrackingActive() const
+    {
+    return ( iTracker != NULL ? iTracker->AmTracking() : EFalse );
+    }
+
+
+EXPORT_C TBool CMemSpyThreadInfoMemoryTracking::TotalIncludesSharedMemory() const
+    {
+    return iTotalIncludesSharedMemory;
+    }
+
+
+EXPORT_C void CMemSpyThreadInfoMemoryTracking::TrackingSetTotalIncludesSharedMemoryL( TBool aIncludesSharedMemory )
+    {
+    iTotalIncludesSharedMemory = aIncludesSharedMemory;
+
+    if  ( iTracker )
+        {
+        iInfoCurrent->SetTotalIncludesSharedMemoryL( aIncludesSharedMemory );
+        iInfoHWM->SetTotalIncludesSharedMemoryL( aIncludesSharedMemory );
+        iInfoPeak->SetTotalIncludesSharedMemoryL( aIncludesSharedMemory );
+        
+        // Update totals
+        TRAP_IGNORE( UpdateCaptionsL( iTracker->InfoCurrent(), iTracker->InfoHWMIncShared(), iTracker->InfoHWMExcShared() ) );
+        }
+    }
+
+
+EXPORT_C void CMemSpyThreadInfoMemoryTracking::TrackingStartL()
+    {
+    if  ( iTracker == NULL )
+        {
+        CMemSpyProcess& process = Container().Thread().Process();
+        CMemSpyEngine& engine = process.Engine();
+        iTracker = &engine.HelperProcess().TrackerL( process );
+
+        // Make sure we are also listening to the tracker!
+        TrackingObserverAddL( *this );
+        //
+        CMemSpyThreadInfoMemoryTrackingStatisticsCurrent* infoCurrent = CMemSpyThreadInfoMemoryTrackingStatisticsCurrent::NewLC( Container(), EFalse );
+        CMemSpyThreadInfoMemoryTrackingStatisticsHWM* infoHWM = CMemSpyThreadInfoMemoryTrackingStatisticsHWM::NewLC( Container(), EFalse );
+        CMemSpyThreadInfoMemoryTrackingStatisticsPeak* infoPeak = CMemSpyThreadInfoMemoryTrackingStatisticsPeak::NewLC( Container(), EFalse );
+        //
+        iInfoCurrent = infoCurrent;
+        iInfoHWM = infoHWM;
+        iInfoPeak = infoPeak;
+        //
+        CleanupStack::Pop( iInfoPeak );
+        CleanupStack::Pop( infoHWM );
+        CleanupStack::Pop( infoCurrent );
+        //
+        TrackingSetTotalIncludesSharedMemoryL( iTotalIncludesSharedMemory );
+        }
+
+    iTracker->StartL();
+
+    UpdateCaptionsL();
+    }
+
+
+EXPORT_C void CMemSpyThreadInfoMemoryTracking::TrackingStopL()
+    {
+    if  ( iTracker != NULL )
+        {
+        iTracker->Stop();
+        }
+
+    UpdateCaptionsL();
+    }
+
+
+EXPORT_C void CMemSpyThreadInfoMemoryTracking::TrackingResetHWML()
+    {
+    if  ( iTracker != NULL )
+        {
+        iTracker->ResetHWML();
+        }
+    }
+
+
+EXPORT_C void CMemSpyThreadInfoMemoryTracking::TrackingObserverAddL( MMemSpyEngineProcessMemoryTrackerObserver& aObserver )
+    {
+#ifdef _DEBUG
+    RDebug::Printf( "CMemSpyThreadInfoMemoryTracking::TrackingObserverAddL() - START - iTracker: 0x%08x, this: 0x%08x", iTracker, this );
+#endif
+
+    if  ( iTracker != NULL )
+        {
+        iTracker->AddObserverL( aObserver );
+        }
+
+#ifdef _DEBUG
+    RDebug::Printf( "CMemSpyThreadInfoMemoryTracking::TrackingObserverAddL() - END - iTracker: 0x%08x, this: 0x%08x", iTracker, this );
+#endif
+    }
+
+
+EXPORT_C void CMemSpyThreadInfoMemoryTracking::TrackingObserverRemove( MMemSpyEngineProcessMemoryTrackerObserver& aObserver )
+    {
+#ifdef _DEBUG
+    RDebug::Printf( "CMemSpyThreadInfoMemoryTracking::TrackingObserverRemove() - START - iTracker: 0x%08x, this: 0x%08x", iTracker, this );
+#endif
+
+    if  ( iTracker != NULL )
+        {
+        iTracker->RemoveObserver( aObserver );
+        }
+
+#ifdef _DEBUG
+    RDebug::Printf( "CMemSpyThreadInfoMemoryTracking::TrackingObserverRemove() - END - iTracker: 0x%08x, this: 0x%08x", iTracker, this );
+#endif
+    }
+
+
+EXPORT_C MDesCArray& CMemSpyThreadInfoMemoryTracking::InfoCurrent()
+    {
+    return *iInfoCurrent;
+    }
+
+
+EXPORT_C MDesCArray& CMemSpyThreadInfoMemoryTracking::InfoHWM()
+    {
+    return *iInfoHWM;
+    }
+
+
+EXPORT_C MDesCArray& CMemSpyThreadInfoMemoryTracking::InfoPeak()
+    {
+    return *iInfoPeak;
+    }
+
+
+void CMemSpyThreadInfoMemoryTracking::HandleMemoryTrackingStartedL()
+    {
+    __ASSERT_ALWAYS( iTracker, MemSpyEngineUtils::Panic( EMemSpyEnginePanicTrackerNull1 ) );
+    CMemSpyThreadInfoItemBase::CItem& trackingItem = Item( 0 );
+    trackingItem.SetOnOffL( iTracker->AmTracking() );
+    //
+    Container().NotifyObserverL( MMemSpyThreadInfoContainerObserver::EInfoItemChanged, Type() );
+    }
+
+
+void CMemSpyThreadInfoMemoryTracking::HandleMemoryTrackingStoppedL()
+    {
+    __ASSERT_ALWAYS( iTracker, MemSpyEngineUtils::Panic( EMemSpyEnginePanicTrackerNull2 ) );
+    CMemSpyThreadInfoItemBase::CItem& trackingItem = Item( 0 );
+    trackingItem.SetOnOffL( iTracker->AmTracking() );
+    //
+    Container().NotifyObserverL( MMemSpyThreadInfoContainerObserver::EInfoItemChanged, Type() );
+    }
+
+
+void CMemSpyThreadInfoMemoryTracking::HandleMemoryChangedL( const TProcessId& /*aPid*/, const TMemSpyDriverProcessInspectionInfo& aInfoCurrent, const TMemSpyDriverProcessInspectionInfo& aHWMInfoIncShared, const TMemSpyDriverProcessInspectionInfo& aHWMInfoExcShared )
+    {
+#ifdef _DEBUG
+    RDebug::Printf( "CMemSpyThreadInfoMemoryTracking::HandleMemoryChangedL() - START - this: 0x%08x", this );
+#endif 
+
+    __ASSERT_ALWAYS( iTracker, MemSpyEngineUtils::Panic( EMemSpyEnginePanicTrackerNull3 ) );
+    UpdateCaptionsL( aInfoCurrent, aHWMInfoIncShared, aHWMInfoExcShared );
+
+#ifdef _DEBUG
+    RDebug::Printf( "CMemSpyThreadInfoMemoryTracking::HandleMemoryChangedL() - END - this: 0x%08x", this );
+#endif 
+    }
+
+
+void CMemSpyThreadInfoMemoryTracking::UpdateCaptionsL()
+    {
+    if  ( iTracker )
+        {
+        UpdateCaptionsL( iTracker->InfoCurrent(), iTracker->InfoHWMIncShared(), iTracker->InfoHWMExcShared() );
+        }
+    }
+
+
+void CMemSpyThreadInfoMemoryTracking::UpdateCaptionsL( const TMemSpyDriverProcessInspectionInfo& aInfoCurrent, const TMemSpyDriverProcessInspectionInfo& aHWMInfoIncShared, const TMemSpyDriverProcessInspectionInfo& aHWMInfoExcShared )
+    {
+    if  ( iTracker )
+        {
+        // Update caption
+        Item( 0 ).SetOnOffL( TrackingActive() );
+  
+        if  ( TotalIncludesSharedMemory() )
+            {
+            Item( 1 ).SetLongL( aInfoCurrent.TotalIncShared() );
+            Item( 2 ).SetLongL( aHWMInfoIncShared.TotalIncShared() );
+            Item( 3 ).SetLongL( iTracker->InfoPeaks().TotalIncShared() );
+            }
+        else
+            {
+            Item( 1 ).SetLongL( aInfoCurrent.TotalExcShared() );
+            Item( 2 ).SetLongL( aHWMInfoExcShared.TotalExcShared() );
+            Item( 3 ).SetLongL( iTracker->InfoPeaks().TotalExcShared() );
+            }
+
+        Container().NotifyObserverL( MMemSpyThreadInfoContainerObserver::EInfoItemChanged, Type() );
+        }
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoMemoryTrackingStatisticsCurrent::CMemSpyThreadInfoMemoryTrackingStatisticsCurrent( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+:   CMemSpyThreadInfoItemBase( aContainer, EMemSpyThreadInfoItemTypeMemoryTrackingCurrent, aAsyncConstruction ), iTotalIncludesSharedMemory( ETrue )
+    {
+    }
+
+
+CMemSpyThreadInfoMemoryTrackingStatisticsCurrent::~CMemSpyThreadInfoMemoryTrackingStatisticsCurrent()
+    {
+    if  ( iTracker )
+        {
+        iTracker->RemoveObserver( *this );
+        }
+    }
+
+
+void CMemSpyThreadInfoMemoryTrackingStatisticsCurrent::ConstructL()
+    {
+    CMemSpyEngine& engine = Container().Thread().Process().Engine();
+    //
+    if  ( iTracker )
+        {
+        iTracker->RemoveObserver( *this );
+        }
+    iTracker = &Container().Engine().HelperProcess().TrackerL( Container().Thread().Process() );
+    if  ( iTracker )
+        {
+        iTracker->AddObserverL( *this );
+        //
+        _LIT( KItem1, "Stack Memory" );
+        AddItemDecimalL( KItem1, iTracker->InfoCurrent().iMemoryStack );
+        //
+        _LIT( KItem2, "Heap Memory" );
+        AddItemDecimalL( KItem2, iTracker->InfoCurrent().iMemoryHeap );
+        //
+        _LIT( KItem3, "Local Chunk Memory" );
+        AddItemDecimalL( KItem3, iTracker->InfoCurrent().iMemoryChunkLocal );
+        //
+        _LIT( KItem4, "Shared Chunk Memory" );
+        AddItemDecimalL( KItem4, iTracker->InfoCurrent().iMemoryChunkShared );
+        //
+        _LIT( KItem5, "Global Data Memory" );
+        AddItemDecimalL( KItem5, iTracker->InfoCurrent().iMemoryGlobalData );
+        //
+        _LIT( KItem6, "Total" );
+        if  ( iTotalIncludesSharedMemory )
+            {
+            AddItemLongL( KItem6, iTracker->InfoCurrent().TotalIncShared() );
+            }
+        else
+            {
+            AddItemLongL( KItem6, iTracker->InfoCurrent().TotalExcShared() );
+            }
+        }
+    }
+
+
+CMemSpyThreadInfoMemoryTrackingStatisticsCurrent* CMemSpyThreadInfoMemoryTrackingStatisticsCurrent::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+    {
+    CMemSpyThreadInfoMemoryTrackingStatisticsCurrent* self = new(ELeave) CMemSpyThreadInfoMemoryTrackingStatisticsCurrent( aContainer, aAsyncConstruction );
+    CleanupStack::PushL( self );
+    if  ( !aAsyncConstruction )
+        {
+        self->ConstructL();
+        }
+    return self;
+    }
+
+
+TPtrC CMemSpyThreadInfoMemoryTrackingStatisticsCurrent::Name() const
+    {
+    _LIT(KName, "\tCurrent Statistics");
+    return TPtrC( KName );
+    }
+
+
+void CMemSpyThreadInfoMemoryTrackingStatisticsCurrent::SetTotalIncludesSharedMemoryL( TBool aIncludesSharedMemory )
+    {
+    iTotalIncludesSharedMemory = aIncludesSharedMemory;
+    
+    // Update totals
+    HandleMemoryChangedL( iTracker->ProcessId(), iTracker->InfoCurrent(), iTracker->InfoHWMIncShared(), iTracker->InfoHWMExcShared() );
+    }
+
+
+void CMemSpyThreadInfoMemoryTrackingStatisticsCurrent::HandleMemoryTrackingStartedL()
+    {
+    }
+
+
+void CMemSpyThreadInfoMemoryTrackingStatisticsCurrent::HandleMemoryTrackingStoppedL()
+    {
+    }
+
+
+void CMemSpyThreadInfoMemoryTrackingStatisticsCurrent::HandleMemoryChangedL( const TProcessId& /*aPid*/, const TMemSpyDriverProcessInspectionInfo& aInfoCurrent, const TMemSpyDriverProcessInspectionInfo& /*aHWMInfoIncShared*/, const TMemSpyDriverProcessInspectionInfo& /*aHWMInfoExcShared*/ )
+    {
+    Item( 0 ).SetDecimalL( aInfoCurrent.iMemoryStack );
+    Item( 1 ).SetDecimalL( aInfoCurrent.iMemoryHeap );
+    Item( 2 ).SetDecimalL( aInfoCurrent.iMemoryChunkLocal );
+    Item( 3 ).SetDecimalL( aInfoCurrent.iMemoryChunkShared );
+    Item( 4 ).SetDecimalL( aInfoCurrent.iMemoryGlobalData );
+    //
+    if  ( iTotalIncludesSharedMemory )
+        {
+        Item( 5 ).SetLongL( aInfoCurrent.TotalIncShared() );
+        }
+    else
+        {
+        Item( 5 ).SetLongL( aInfoCurrent.TotalExcShared() );
+        }
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoMemoryTrackingStatisticsPeak::CMemSpyThreadInfoMemoryTrackingStatisticsPeak( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+:   CMemSpyThreadInfoItemBase( aContainer, EMemSpyThreadInfoItemTypeMemoryTrackingPeak, aAsyncConstruction ), iTotalIncludesSharedMemory( ETrue )
+    {
+    }
+
+
+CMemSpyThreadInfoMemoryTrackingStatisticsPeak::~CMemSpyThreadInfoMemoryTrackingStatisticsPeak()
+    {
+    if  ( iTracker )
+        {
+        iTracker->RemoveObserver( *this );
+        }
+    }
+
+
+void CMemSpyThreadInfoMemoryTrackingStatisticsPeak::ConstructL()
+    {
+    CMemSpyEngine& engine = Container().Thread().Process().Engine();
+    //
+    if  ( iTracker )
+        {
+        iTracker->RemoveObserver( *this );
+        }
+    iTracker = &Container().Engine().HelperProcess().TrackerL( Container().Thread().Process() );
+    if  ( iTracker )
+        {
+        iTracker->AddObserverL( *this );
+        //
+        _LIT( KItem1, "Stack Memory" );
+        AddItemDecimalL( KItem1, iTracker->InfoPeaks().iMemoryStack );
+        //
+        _LIT( KItem2, "Heap Memory" );
+        AddItemDecimalL( KItem2, iTracker->InfoPeaks().iMemoryHeap );
+        //
+        _LIT( KItem3, "Local Chunk Memory" );
+        AddItemDecimalL( KItem3, iTracker->InfoPeaks().iMemoryChunkLocal );
+        //
+        _LIT( KItem4, "Shared Chunk Memory" );
+        AddItemDecimalL( KItem4, iTracker->InfoPeaks().iMemoryChunkShared );
+        //
+        _LIT( KItem5, "Global Data Memory" );
+        AddItemDecimalL( KItem5, iTracker->InfoPeaks().iMemoryGlobalData );
+        //
+        _LIT( KItem6, "Total" );
+        if  ( iTotalIncludesSharedMemory )
+            {
+            AddItemLongL( KItem6, iTracker->InfoPeaks().TotalIncShared() );
+            }
+        else
+            {
+            AddItemLongL( KItem6, iTracker->InfoPeaks().TotalExcShared() );
+            }
+        }
+    }
+
+
+CMemSpyThreadInfoMemoryTrackingStatisticsPeak* CMemSpyThreadInfoMemoryTrackingStatisticsPeak::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+    {
+    CMemSpyThreadInfoMemoryTrackingStatisticsPeak* self = new(ELeave) CMemSpyThreadInfoMemoryTrackingStatisticsPeak( aContainer, aAsyncConstruction );
+    CleanupStack::PushL( self );
+    if  ( !aAsyncConstruction )
+        {
+        self->ConstructL();
+        }
+    return self;
+    }
+
+
+TPtrC CMemSpyThreadInfoMemoryTrackingStatisticsPeak::Name() const
+    {
+    _LIT(KName, "\tPeak Statistics");
+    return TPtrC( KName );
+    }
+
+
+void CMemSpyThreadInfoMemoryTrackingStatisticsPeak::SetTotalIncludesSharedMemoryL( TBool aIncludesSharedMemory )
+    {
+    iTotalIncludesSharedMemory = aIncludesSharedMemory;
+    
+    // Update totals
+    HandleMemoryChangedL( iTracker->ProcessId(), iTracker->InfoCurrent(), iTracker->InfoHWMIncShared(), iTracker->InfoHWMExcShared() );
+    }
+
+
+void CMemSpyThreadInfoMemoryTrackingStatisticsPeak::HandleMemoryTrackingStartedL()
+    {
+    }
+
+
+void CMemSpyThreadInfoMemoryTrackingStatisticsPeak::HandleMemoryTrackingStoppedL()
+    {
+    }
+
+
+void CMemSpyThreadInfoMemoryTrackingStatisticsPeak::HandleMemoryChangedL( const TProcessId& /*aPid*/, const TMemSpyDriverProcessInspectionInfo& /*aInfoCurrent*/, const TMemSpyDriverProcessInspectionInfo& /*aHWMInfoIncShared*/, const TMemSpyDriverProcessInspectionInfo& /*aHWMInfoExcShared*/ )
+    {
+    Item( 0 ).SetDecimalL( iTracker->InfoPeaks().iMemoryStack );
+    Item( 1 ).SetDecimalL( iTracker->InfoPeaks().iMemoryHeap );
+    Item( 2 ).SetDecimalL( iTracker->InfoPeaks().iMemoryChunkLocal );
+    Item( 3 ).SetDecimalL( iTracker->InfoPeaks().iMemoryChunkShared );
+    Item( 4 ).SetDecimalL( iTracker->InfoPeaks().iMemoryGlobalData );
+    //
+    if ( iTotalIncludesSharedMemory )
+        {
+        Item( 5 ).SetLongL( iTracker->InfoPeaks().TotalIncShared() );
+        }
+    else
+        {
+        Item( 5 ).SetLongL( iTracker->InfoPeaks().TotalExcShared() );
+        }
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CMemSpyThreadInfoMemoryTrackingStatisticsHWM::CMemSpyThreadInfoMemoryTrackingStatisticsHWM( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+:   CMemSpyThreadInfoItemBase( aContainer, EMemSpyThreadInfoItemTypeMemoryTrackingHWM, aAsyncConstruction ), iTotalIncludesSharedMemory( ETrue )
+    {
+    }
+
+
+CMemSpyThreadInfoMemoryTrackingStatisticsHWM::~CMemSpyThreadInfoMemoryTrackingStatisticsHWM()
+    {
+    if  ( iTracker )
+        {
+        iTracker->RemoveObserver( *this );
+        }
+    }
+
+
+void CMemSpyThreadInfoMemoryTrackingStatisticsHWM::ConstructL()
+    {
+    CMemSpyEngine& engine = Container().Thread().Process().Engine();
+    //
+    if  ( iTracker )
+        {
+        iTracker->RemoveObserver( *this );
+        }
+    iTracker = &Container().Engine().HelperProcess().TrackerL( Container().Thread().Process() );
+    if  ( iTracker )
+        {
+        iTracker->AddObserverL( *this );
+        //
+        _LIT( KItem1, "Stack Memory" );
+        _LIT( KItem2, "Heap Memory" );
+        _LIT( KItem3, "Local Chunk Memory" );
+        _LIT( KItem4, "Shared Chunk Memory" );
+        _LIT( KItem5, "Global Data Memory" );
+        _LIT( KItem6, "Total" );
+        //
+        if  ( iTotalIncludesSharedMemory )
+            {
+            AddItemDecimalL( KItem1, iTracker->InfoHWMIncShared().iMemoryStack );
+            AddItemDecimalL( KItem2, iTracker->InfoHWMIncShared().iMemoryHeap );
+            AddItemDecimalL( KItem3, iTracker->InfoHWMIncShared().iMemoryChunkLocal );
+            AddItemDecimalL( KItem4, iTracker->InfoHWMIncShared().iMemoryChunkShared );
+            AddItemDecimalL( KItem5, iTracker->InfoHWMIncShared().iMemoryGlobalData );
+            AddItemLongL(    KItem6, iTracker->InfoHWMIncShared().TotalIncShared() );
+            }
+        else
+            {
+            AddItemDecimalL( KItem1, iTracker->InfoHWMExcShared().iMemoryStack );
+            AddItemDecimalL( KItem2, iTracker->InfoHWMExcShared().iMemoryHeap );
+            AddItemDecimalL( KItem3, iTracker->InfoHWMExcShared().iMemoryChunkLocal );
+            AddItemDecimalL( KItem4, iTracker->InfoHWMExcShared().iMemoryChunkShared );
+            AddItemDecimalL( KItem5, iTracker->InfoHWMExcShared().iMemoryGlobalData );
+            AddItemLongL(    KItem6, iTracker->InfoHWMExcShared().TotalExcShared() );
+            }
+        }
+    }
+
+
+CMemSpyThreadInfoMemoryTrackingStatisticsHWM* CMemSpyThreadInfoMemoryTrackingStatisticsHWM::NewLC( CMemSpyThreadInfoContainer& aContainer, TBool aAsyncConstruction )
+    {
+    CMemSpyThreadInfoMemoryTrackingStatisticsHWM* self = new(ELeave) CMemSpyThreadInfoMemoryTrackingStatisticsHWM( aContainer, aAsyncConstruction );
+    CleanupStack::PushL( self );
+    if  ( !aAsyncConstruction )
+        {
+        self->ConstructL();
+        }
+    return self;
+    }
+
+
+void CMemSpyThreadInfoMemoryTrackingStatisticsHWM::SetTotalIncludesSharedMemoryL( TBool aIncludesSharedMemory )
+    {
+    iTotalIncludesSharedMemory = aIncludesSharedMemory;
+    
+    // Update totals
+    HandleMemoryChangedL( iTracker->ProcessId(), iTracker->InfoCurrent(), iTracker->InfoHWMIncShared(), iTracker->InfoHWMExcShared() );
+    }
+
+
+TPtrC CMemSpyThreadInfoMemoryTrackingStatisticsHWM::Name() const
+    {
+    _LIT(KName, "\tHigh-Water-Mark Statistics");
+    return TPtrC( KName );
+    }
+
+
+void CMemSpyThreadInfoMemoryTrackingStatisticsHWM::HandleMemoryTrackingStartedL()
+    {
+    }
+
+
+void CMemSpyThreadInfoMemoryTrackingStatisticsHWM::HandleMemoryTrackingStoppedL()
+    {
+    }
+
+
+void CMemSpyThreadInfoMemoryTrackingStatisticsHWM::HandleMemoryChangedL( const TProcessId& /*aPid*/, const TMemSpyDriverProcessInspectionInfo& /*aInfoCurrent*/, const TMemSpyDriverProcessInspectionInfo& aHWMInfoIncShared, const TMemSpyDriverProcessInspectionInfo& aHWMInfoExcShared )
+    {
+    if  ( iTotalIncludesSharedMemory )
+        {
+        Item( 0 ).SetDecimalL( aHWMInfoIncShared.iMemoryStack );
+        Item( 1 ).SetDecimalL( aHWMInfoIncShared.iMemoryHeap );
+        Item( 2 ).SetDecimalL( aHWMInfoIncShared.iMemoryChunkLocal );
+        Item( 3 ).SetDecimalL( aHWMInfoIncShared.iMemoryChunkShared );
+        Item( 4 ).SetDecimalL( aHWMInfoIncShared.iMemoryGlobalData );
+        Item( 5 ).SetLongL(    aHWMInfoIncShared.TotalIncShared() );
+        }
+    else
+        {
+        Item( 0 ).SetDecimalL( aHWMInfoExcShared.iMemoryStack );
+        Item( 1 ).SetDecimalL( aHWMInfoExcShared.iMemoryHeap );
+        Item( 2 ).SetDecimalL( aHWMInfoExcShared.iMemoryChunkLocal );
+        Item( 3 ).SetDecimalL( aHWMInfoExcShared.iMemoryChunkShared );
+        Item( 4 ).SetDecimalL( aHWMInfoExcShared.iMemoryGlobalData );
+        Item( 5 ).SetLongL(    aHWMInfoExcShared.TotalExcShared() );
+        }
+    }