Click here to Skip to main content
15,883,849 members
Articles / Desktop Programming / MFC

Task Manager Extension 2.0

Rate me:
Please Sign up or sign in to vote.
4.92/5 (149 votes)
22 Jan 2007CDDL11 min read 597K   18.7K   263  
Task Manager Extension. This is a Windows Task Manager (NT/2000/XP/2003) plug-in. It adds lots of useful features to the standard Task Manager. It can show process modules, memory map, used handles, open files, file properties and a lot of other info!
// CSystemInfoListCtrl.cpp : implementation file
//

#include "stdafx.h"
#include "taskmanagerexdll.h"
#include "SystemInfoListCtrl.h"
#include "resource.h"
#include "Localization.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

static char g_szStamp_Mark[] = "\r\n\r\nSystemInfoListCtrl.cpp Timestamp: " __DATE__ ", " __TIME__ "\r\n\r\n";

////////////////////////////////////////////////////////////////////////////
// CReportHeaderCtrl implementation
////////////////////////////////////////////////////////////////////////////
CSystemInfoListCtrl::CReportHeaderCtrl::CReportHeaderCtrl()
{
	m_iSortColumn = -1;
	m_bSortAscending = TRUE;
}

int CSystemInfoListCtrl::CReportHeaderCtrl::GetSortedColumn() const
{
	return m_iSortColumn;
}

BOOL CSystemInfoListCtrl::CReportHeaderCtrl::IsSortAscending() const
{
	return m_bSortAscending;
}

void CSystemInfoListCtrl::CReportHeaderCtrl::SetSortAscending(BOOL bAscending)
{
	m_bSortAscending = bAscending;
}

void CSystemInfoListCtrl::CReportHeaderCtrl::SetSortedColumn(int nCol)
{
	m_iSortColumn = nCol;
}

////////////////////////////////////////////////////////////////////////////////
// Mark Jackson's code
////////////////////////////////////////////////////////////////////////////////
void CSystemInfoListCtrl::CReportHeaderCtrl::UpdateSortArrow()
{
	// change the item to owner drawn.
	HD_ITEM hditem;

	if( m_iSortColumn != -1 )
	{
		hditem.mask = HDI_FORMAT;
		VERIFY(GetItem(m_iSortColumn, &hditem));
		hditem.fmt |= HDF_OWNERDRAW;
		VERIFY(SetItem(m_iSortColumn, &hditem));
	}

	// invalidate the header control so it gets redrawn
	Invalidate();
}

////////////////////////////////////////////////////////////////////////////////
// Mark Jackson's code
////////////////////////////////////////////////////////////////////////////////
void CSystemInfoListCtrl::CReportHeaderCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
	// attath to the device context.
	CDC dc;
	VERIFY(dc.Attach(lpDrawItemStruct->hDC));

	// save the device context.
	const int iSavedDC = dc.SaveDC();

	// get the column rect.
	CRect rc(lpDrawItemStruct->rcItem);

	// set the clipping region to limit drawing within the column.
	CRgn rgn;
	VERIFY(rgn.CreateRectRgnIndirect(&rc));
	(void)dc.SelectObject(&rgn);
	VERIFY(rgn.DeleteObject());

	// draw the background,
	CBrush brush(GetSysColor(COLOR_3DFACE));
	dc.FillRect(rc, &brush);

	// get the column text and format.
	TCHAR szText[ 256 ];
	HD_ITEM hditem;

	hditem.mask = HDI_TEXT | HDI_FORMAT;
	hditem.pszText = szText;
	hditem.cchTextMax = 255;

	VERIFY(GetItem(lpDrawItemStruct->itemID, &hditem));

	// determine the format for drawing the column label.
	UINT uFormat = DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_END_ELLIPSIS ;

	if(hditem.fmt & HDF_CENTER)
		uFormat |= DT_CENTER;
	else if(hditem.fmt & HDF_RIGHT)
		uFormat |= DT_RIGHT;
	else
		uFormat |= DT_LEFT;

	// adjust the rect if the mouse button is pressed on it.
	if(lpDrawItemStruct->itemState == ODS_SELECTED)
	{
		rc.left++;
		rc.top += 2;
		rc.right++;
	}

	CRect rcIcon(lpDrawItemStruct->rcItem);
	const int iOffset = (rcIcon.bottom - rcIcon.top) / 4;

	// adjust the rect further if the sort arrow is to be displayed.
	if(lpDrawItemStruct->itemID == (UINT)m_iSortColumn)
		rc.right -= 3 * iOffset;

	rc.left += iOffset;
	rc.right -= iOffset;

	// draw the column label.
	if(rc.left < rc.right)
		(void)dc.DrawText(szText, -1, rc, uFormat);

	// draw the sort arrow.
	if(lpDrawItemStruct->itemID == (UINT)m_iSortColumn)
	{
		// set up the pens to use for drawing the arrow.
		CPen penLight(PS_SOLID, 1, GetSysColor(COLOR_3DHILIGHT));
		CPen penShadow(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW));
		CPen* pOldPen = dc.SelectObject(&penLight);

		if(m_bSortAscending)
		{
			// draw the arrow pointing upwards.
			dc.MoveTo(rcIcon.right - 2 * iOffset, iOffset);
			dc.LineTo(rcIcon.right - iOffset, rcIcon.bottom - iOffset - 1);
			dc.LineTo(rcIcon.right - 3 * iOffset - 2, rcIcon.bottom - iOffset - 1);
			(void)dc.SelectObject(&penShadow);
			dc.MoveTo(rcIcon.right - 3 * iOffset - 1, rcIcon.bottom - iOffset - 1);
			dc.LineTo(rcIcon.right - 2 * iOffset, iOffset - 1);		
		}
		else
		{
			// draw the arrow pointing downwards.
			dc.MoveTo(rcIcon.right - iOffset - 1, iOffset);
			dc.LineTo(rcIcon.right - 2 * iOffset - 1, rcIcon.bottom - iOffset);
			(void)dc.SelectObject(&penShadow);
			dc.MoveTo(rcIcon.right - 2 * iOffset - 2, rcIcon.bottom - iOffset);
			dc.LineTo(rcIcon.right - 3 * iOffset - 1, iOffset);
			dc.LineTo(rcIcon.right - iOffset - 1, iOffset);		
		}

		// restore the pen.
		(void)dc.SelectObject(pOldPen);
	}

	// restore the previous device context.
	VERIFY(dc.RestoreDC(iSavedDC));

	// detach the device context before returning.
	(void)dc.Detach();
}


////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// CSystemInfoListCtrl implementation
////////////////////////////////////////////////////////////////////////////

CSystemInfoListCtrl::CSystemInfoListCtrl()
{
	SetSortedColumn( -1 );
	SetSortAscending( TRUE );
}

CSystemInfoListCtrl::~CSystemInfoListCtrl()
{
}


BEGIN_MESSAGE_MAP(CSystemInfoListCtrl, CListCtrl)
	//{{AFX_MSG_MAP(CSystemInfoListCtrl)
	ON_WM_CREATE()
	ON_WM_CONTEXTMENU()
	ON_WM_PAINT()
	ON_WM_SIZE()
	//}}AFX_MSG_MAP
	ON_NOTIFY(HDN_ITEMCLICKA, 0, OnHeaderClicked) 
	ON_NOTIFY(HDN_ITEMCLICKW, 0, OnHeaderClicked)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CSystemInfoListCtrl message handlers

int CSystemInfoListCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CListCtrl::OnCreate(lpCreateStruct) == -1)
		return -1;

	return 0;
}

void CSystemInfoListCtrl::PreSubclassWindow() 
{
	// the list control must have the report style.
	ASSERT(GetStyle() & LVS_REPORT);

	CListCtrl::PreSubclassWindow();
	VERIFY(m_wndHeader.SubclassWindow(GetHeaderCtrl()->GetSafeHwnd()));

	ModifyStyle( 0,
		LVS_REPORT |
		LVS_SHOWSELALWAYS |
//		LVS_SINGLESEL |
		0
		);

	SetExtendedStyle( GetExtendedStyle() |
		LVS_EX_FULLROWSELECT |
		LVS_EX_HEADERDRAGDROP |
		LVS_EX_GRIDLINES |
		LVS_EX_INFOTIP |
//		LVS_EX_ONECLICKACTIVATE |
//		LVS_EX_UNDERLINEHOT |
//		LVS_EX_TRACKSELECT |
//		LVS_EX_FLATSB |
		0
		);

	CListCtrl::PreSubclassWindow();
}

void CSystemInfoListCtrl::ReSort()
{
	HDITEM hi;
	::ZeroMemory( &hi, sizeof(hi) );
	hi.mask = HDI_FORMAT;
	int iCol = GetSortedColumn();
	BOOL bAscending = IsSortAscending();
	m_wndHeader.GetItem( iCol, &hi );

	CSortClass csc(this, iCol, (hi.fmt & LVCFMT_RIGHT)!=0 );

	// show the appropriate arrow in the header control.
	m_wndHeader.UpdateSortArrow();

	csc.Sort( bAscending == TRUE );
}

void CSystemInfoListCtrl::OnHeaderClicked(NMHDR* pNMHDR, LRESULT* pResult) 
{
   HD_NOTIFY *phdn = (HD_NOTIFY *) pNMHDR;

   if( phdn->iButton == 0 )
   {
		// User clicked on header using left mouse button
		int iCol = GetSortedColumn();
		BOOL bAscending = IsSortAscending();

		if( phdn->iItem == iCol )
			SetSortAscending( !bAscending );
		else
			SetSortAscending( TRUE );

		SetSortedColumn( phdn->iItem );

		ReSort();
   }

	*pResult = 0;
}

int CSystemInfoListCtrl::FindColumn( LPCTSTR lpszColumn )
{
   int nCol = -1;
   HDITEM headerInfo;
   TCHAR  lpBuffer[256];

   headerInfo.mask = HDI_TEXT;
   headerInfo.pszText = lpBuffer;
   headerInfo.cchTextMax = 256;

   for ( int i = 0; i < m_wndHeader.GetItemCount(); i++ )
   {
      m_wndHeader.GetItem( i, &headerInfo );

      if ( _tcscmp( lpszColumn, headerInfo.pszText ) == 0 )
         return i;
   }

   return nCol;   
}

BOOL CSystemInfoListCtrl::GetSubItemText( int nPos, LPCTSTR lpszColumn, CString& subItemText )
{
   int nCol = FindColumn( lpszColumn );

   if ( nCol == -1 )
      return FALSE;

   subItemText = GetItemText( nPos, nCol );

   return TRUE;
}

BOOL CSystemInfoListCtrl::GetSelectedSubItemText( int nCol, CString& subItemText )
{
   POSITION pos = GetFirstSelectedItemPosition();

   if ( pos == NULL )
      return FALSE;

   subItemText = GetItemText( GetNextSelectedItem( pos ), nCol );

   return pos == NULL;
}

int CSystemInfoListCtrl::GetSelectedItem()
{
	POSITION pos = GetFirstSelectedItemPosition();

	if ( pos == NULL )
		return -1;

	int iItem = GetNextSelectedItem( pos );

	return iItem;
}

void CSystemInfoListCtrl::SetSelectedItem( int nItem )
{
	int iLastSelected = GetSelectedItem();
	if( iLastSelected == nItem )
	{
		return;
	}

	if( iLastSelected != -1 )
	{
		SetItemState( iLastSelected, 0, LVIS_SELECTED );
	}

	if( nItem != -1 )
	{
		SetItemState( nItem, LVIS_SELECTED, LVIS_SELECTED );
	}
}

BOOL CSystemInfoListCtrl::GetSelectedSubItemText( LPCTSTR lpszColumn, CString& subItemText )
{
   int nCol = FindColumn( lpszColumn );

   if ( nCol == -1 )
      return FALSE;

   return GetSelectedSubItemText( nCol, subItemText );
}

void CSystemInfoListCtrl::OnContextMenu(CWnd* pWnd, CPoint) 
{
   GetParent()->SendMessage( WM_CONTEXTMENU, (WPARAM)pWnd->GetSafeHwnd() );
}

void CSystemInfoListCtrl::OnPaint() 
{
	CListCtrl::OnPaint();
	//Default();

	if (GetItemCount() <= 0)
	{
		COLORREF clrText = ::GetSysColor(COLOR_WINDOWTEXT);
		COLORREF clrTextBk = ::GetSysColor(COLOR_WINDOW);

		CDC* pDC = GetDC();
		// Save dc state
		int nSavedDC = pDC->SaveDC();

		CRect rc;
		GetWindowRect(&rc);
		ScreenToClient(&rc);

		CHeaderCtrl* pHC;
		pHC = &m_wndHeader;
		if (pHC != NULL)
		{
			CRect rcH;
			pHC->GetItemRect(0, &rcH);
			rc.top += rcH.bottom;
		}
		rc.top += 10;

		CString strText;
		strText = LocLoadString( IDS_LIST_NO_ITEMS );
		CBrush brushTextBk(clrTextBk);

		pDC->SetTextColor(clrText);
		pDC->SetBkColor(clrTextBk);
		pDC->FillRect(rc, &brushTextBk);
		pDC->SelectStockObject(ANSI_VAR_FONT);
		pDC->DrawText(strText, -1, rc, 
					  DT_CENTER | DT_WORDBREAK | DT_NOPREFIX | DT_NOCLIP);

		// Restore dc
		pDC->RestoreDC(nSavedDC);
		ReleaseDC(pDC);
	}
	// Do not call CListCtrl::OnPaint() for painting messages
}


/////////////////////////////////////////////////////////////////////////////
// CSortClass

CSortClass::CSortClass(CListCtrl * _pWnd, const int _iCol, const bool _bIsNumeric)
{
	iCol = _iCol;
	pWnd = _pWnd;
	bIsNumeric = _bIsNumeric;
	
	ASSERT(pWnd);
	int max = pWnd->GetItemCount();
	DWORD dw;
	CString txt;
	if (bIsNumeric)
	{
		for (int t = 0; t < max; t++)
		{
			LVITEM item;
			item.iItem = t;
			item.iSubItem = 0;
			item.mask = LVIF_INDENT;
			item.iIndent = 0;
			pWnd->GetItem( &item );

			dw = pWnd->GetItemData(t);
			txt = pWnd->GetItemText(t, iCol);
			pWnd->SetItemData(t, (DWORD) new CSortItemInt(dw, item.iIndent, txt));
		}
	}
	else
	{
		for (int t = 0; t < max; t++)
		{
			LVITEM item;
			item.iItem = t;
			item.iSubItem = 0;
			item.mask = LVIF_INDENT;
			item.iIndent = 0;
			pWnd->GetItem( &item );

			dw = pWnd->GetItemData(t);
			txt = pWnd->GetItemText(t, iCol);
			pWnd->SetItemData(t, (DWORD) new CSortItem(dw, item.iIndent, txt));
		}
	}
}

CSortClass::~CSortClass()
{
	ASSERT(pWnd);
	int max = pWnd->GetItemCount();
	if (bIsNumeric)
	{
		CSortItemInt * pItem;
		for (int t = 0; t < max; t++)
		{
			pItem = (CSortItemInt *) pWnd->GetItemData(t);
			ASSERT(pItem);
			pWnd->SetItemData(t, pItem->dw);
			delete pItem;
		}
	}
	else
	{
		CSortItem * pItem;
		for (int t = 0; t < max; t++)
		{
			pItem = (CSortItem *) pWnd->GetItemData(t);
			ASSERT(pItem);
			pWnd->SetItemData(t, pItem->dw);
			delete pItem;
		}
	}
}

void
CSortClass::Sort(const bool bAsc)
{
	if (bIsNumeric)
	{
		if (bAsc)
			pWnd->SortItems(CompareAscI, 0L);
		else
			pWnd->SortItems(CompareDesI, 0L);
	}
	else
	{
		if (bAsc)
			pWnd->SortItems(CompareAsc, 0L);
		else
			pWnd->SortItems(CompareDes, 0L);
	}
}

int CALLBACK CSortClass::CompareAsc(LPARAM lParam1, LPARAM lParam2, LPARAM )
{
	CSortItem * i1 = (CSortItem *) lParam1;
	CSortItem * i2 = (CSortItem *) lParam2;
	ASSERT(i1 && i2);
	int res = i1->txt.CompareNoCase(i2->txt);
	if( res == 0 )
	{
		if( i1->indent == i2->indent )
			res = 0;
		else if( i1->indent > i2->indent )
			res = 1;
		else
			res = -1;
	}
	return res;
}

int CALLBACK CSortClass::CompareDes(LPARAM lParam1, LPARAM lParam2, LPARAM l3 )
{
	int res = CompareAsc( lParam1, lParam2, l3 );
	return -res;
}

int CALLBACK CSortClass::CompareAscI(LPARAM lParam1, LPARAM lParam2, LPARAM )
{
	CSortItemInt * i1 = (CSortItemInt *) lParam1;
	CSortItemInt * i2 = (CSortItemInt *) lParam2;
	ASSERT(i1 && i2);

	int res = 0;
	if (i1->iInt == i2->iInt)
	{
		if( i1->indent == i2->indent )
			res = 0;
		else if( i1->indent > i2->indent )
			res = 1;
		else
			res = -1;
	}
	else
	{
		res = i1->iInt > i2->iInt ? 1 : -1;
	}
	return res;
}

int CALLBACK CSortClass::CompareDesI(LPARAM lParam1, LPARAM lParam2, LPARAM l3 )
{
	int res = CompareAscI( lParam1, lParam2, l3 );
	return -res;
}

CSortClass::CSortItem::CSortItem( DWORD _dw, int _indent, const CString & _txt)
{
	dw = _dw;
	indent = _indent;
	txt = _txt;
}

CSortClass::CSortItem::~CSortItem()
{
}

CSortClass::CSortItemInt::CSortItemInt( DWORD _dw, int _indent, const CString & _txt)
{
	iInt = _ttoi(_txt);
	indent = _indent;
	dw = _dw;
}

void CSystemInfoListCtrl::OnSize(UINT nType, int cx, int cy) 
{
	CListCtrl::OnSize(nType, cx, cy);

//	this->InvalidateRect( NULL );
}

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

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

License

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


Written By
Software Developer (Senior)
Belarus Belarus
He is a young and forward-looking software developer. He also has lots of interesting hobbies like snowboarding, bicycle riding, carting racing and of course talking about himself in a third person. Smile | :)

github.com/kolomenkin

Curriculum Vitae

Comments and Discussions