Click here to Skip to main content
15,888,521 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 597.5K   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!
// ProcessInfoDlg.cpp : implementation file
//

#include "stdafx.h"
#include "InformationDlg.h"
#include "TaskManagerExDll.h"
#include "Localization.h"
#include "AboutExtension.h"

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

/////////////////////////////////////////////////////////////////////////////

IMPLEMENT_DYNCREATE( CInformationDlgThread, CWinThread )

BOOL CInformationDlgThread::InitInstance()
{
	SetThreadNativeLanguage();
	CInformationDlg dlg;
	m_pMainWnd = &dlg;

	dlg.DoModal();

	PostQuitMessage( 0 ); // quit thread gracefully
	return TRUE;
//	return FALSE; // return error to quit thread
}

BOOL CInformationDlgThread::Initialize( DWORD pID, WPARAM command )
{
	m_processID = pID;
	m_command = command;

	return TRUE;
}

CInformationDlgThread* CInformationDlgThread::Start( DWORD pID, WPARAM command )
{
   CInformationDlgThread* _this = (CInformationDlgThread*)::AfxBeginThread(
                  RUNTIME_CLASS(CInformationDlgThread),
                  THREAD_PRIORITY_NORMAL,
                  0,
                  CREATE_SUSPENDED );

   _this->Initialize( pID, command );

   _this->ResumeThread();

   return _this;
}

/////////////////////////////////////////////////////////////////////////////
// CInformationDlg dialog


CInformationDlg::CInformationDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CInformationDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CInformationDlg)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT
	m_OldClientSize = CSize(0,0);
}


void CInformationDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CInformationDlg)
	DDX_Control(pDX, IDC_EXIT, m_wndExit);
	DDX_Control(pDX, IDC_INFO, m_wndInfo);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CInformationDlg, CDialog)
	//{{AFX_MSG_MAP(CInformationDlg)
	ON_WM_CLOSE()
	ON_WM_DESTROY()
	ON_BN_CLICKED(IDC_EXIT, OnExit)
	ON_BN_CLICKED(IDC_REFRESH, OnRefresh)
	ON_WM_HELPINFO()
	ON_WM_SIZE()
	ON_WM_PAINT()
	ON_WM_GETMINMAXINFO()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CInformationDlg message handlers

void CInformationDlg::OnClose()
{
	CDialog::OnClose();
}

void CInformationDlg::OnDestroy()
{
	CDialog::OnDestroy();

	m_Font.DeleteObject();
}

void CInformationDlg::OnOK()
{
//	CDialog::OnOK();
//	OnRefresh();
}

void CInformationDlg::OnCancel()
{
	CDialog::OnCancel();
}

void CInformationDlg::OnExit()
{
	EndDialog( IDOK );
}

/////////////////////////////////////////////////////////////////////////////

BOOL CInformationDlg::PreTranslateMessage(MSG* pMsg) 
{
	// CG: The following block was added by the ToolTips component.
	{
		// Let the ToolTip process this message.
		m_tooltip.RelayEvent(pMsg);
	}

	return CDialog::PreTranslateMessage(pMsg);
}

/////////////////////////////////////////////////////////////////////////////

BOOL CInformationDlg::OnHelpInfo(HELPINFO* pHelpInfo) 
{
	pHelpInfo = pHelpInfo;
	CAboutExtensionThread::Start();
	return TRUE;
	//return CDialog::OnHelpInfo(pHelpInfo);
}

/////////////////////////////////////////////////////////////////////////////

int CInformationDlg::DoModal() 
{
	// load resource as necessary
	if( m_lpszTemplateName != NULL && m_lpDialogTemplate == NULL )
	{
		m_lpDialogTemplate = LocLoadDialog( m_lpszTemplateName );
		m_lpszTemplateName = NULL;
	}

	return CDialog::DoModal();
}

/////////////////////////////////////////////////////////////////////////////

void CInformationDlg::OnSize(UINT nType, int cx, int cy) 
{
	CDialog::OnSize(nType, cx, cy);

	if( ::IsWindow( m_wndInfo.m_hWnd ) )
	{
		CRect r;
		m_wndInfo.GetWindowRect( &r );
		ScreenToClient( &r );
		r.right += cx - m_OldClientSize.cx;
		r.bottom += cy - m_OldClientSize.cy;
		m_wndInfo.MoveWindow( &r );
	}

	if( ::IsWindow( m_wndExit.m_hWnd ) )
	{
		CRect r;
		m_wndExit.GetWindowRect( &r );
		ScreenToClient( &r );
		r += CPoint( cx - m_OldClientSize.cx, 0 );
		m_wndExit.MoveWindow( &r );
		m_wndExit.RedrawWindow();
	}

	m_OldClientSize.cx = cx;
	m_OldClientSize.cy = cy;
}

/////////////////////////////////////////////////////////////////////////////

void CInformationDlg::OnGetMinMaxInfo( MINMAXINFO* pMinMaxInfo )
{
	CDialog::OnGetMinMaxInfo( pMinMaxInfo );
	pMinMaxInfo->ptMinTrackSize = CPoint( 300, 200 );
}

/////////////////////////////////////////////////////////////////////////////

BOOL CInformationDlg::OnInitDialog() 
{
	CInformationDlgThread* pThread = (CInformationDlgThread*)AfxGetThread();

	CDialog::OnInitDialog();

	SetIcon( theApp.hMainIconBig, TRUE );
	SetIcon( theApp.hMainIconSmall, FALSE );
//	SetClassLong( this->GetSafeHwnd(), GCL_HICON, (long)theApp.hMainIconBig );		// this changes icon for any dialog in the process!
//	SetClassLong( this->GetSafeHwnd(), GCL_HICONSM, (long)theApp.hMainIconSmall );	// this changes icon for any dialog in the process!

	m_Font.CreateFont(16, 0, 0, 0, 0, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0,	0,
		_T("Courier New") );

	const int iCharTabStop = 4;
	const int iDlgTabStop = (iCharTabStop*32+3)/6; // Only for 16x "Courier New"!

	m_wndInfo.SetTabStops( iDlgTabStop );
	m_wndInfo.SetFont( &m_Font );


	// CG: The following block was added by the ToolTips component.
	{
		// Create the ToolTip control.
		m_tooltip.Create(this);
		m_tooltip.Activate(TRUE);

		m_tooltip.AddTool( GetDlgItem(IDC_EXIT), LocLoadString(IDC_INFO_EXIT) );
		m_tooltip.AddTool( GetDlgItem(IDC_REFRESH ), LocLoadString(IDC_INFO_REFRESH) );

		// TODO: Use one of the following forms to add controls:
		// m_tooltip.AddTool(GetDlgItem(IDC_<name>), <string-table-id>);
		// m_tooltip.AddTool(GetDlgItem(IDC_<name>), "<text>");
	}

	CString strCaption = _T("Unknown");

	switch( pThread->m_command )
	{
	case ID_PROCESSES_INFO:
		{
			TCHAR szFileName[MAX_PATH] = _T("");
			GetProcessExecutableName( pThread->m_processID, szFileName, SIZEOF_ARRAY(szFileName) );
			CString s = szFileName;
			int pos = s.ReverseFind( _T('\\') );

			strCaption.Format( _T("PID = %d(0x%X) - %s - "),
				pThread->m_processID, pThread->m_processID, s.Mid(pos+1) );
		}
		break;
	}

	switch( pThread->m_command )
	{
	case ID_PROCESSES_INFO:

		strCaption += LocLoadString(IDS_INFORMATION_RPOCESS);
		break;
	}

	SetWindowText( strCaption );
	OnRefresh();

	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

/////////////////////////////////////////////////////////////////////////////

void CInformationDlg::OnRefresh()
{
	CInformationDlgThread* pThread = (CInformationDlgThread*)AfxGetThread();

	int x = m_wndInfo.GetScrollPos( SB_HORZ );
	int y = m_wndInfo.GetScrollPos( SB_VERT );

	int iCharWidth = 1;
	{
		CDC dc;
		dc.CreateCompatibleDC( GetDC() );
		CFont* pOldFont = dc.SelectObject( &m_Font );
		iCharWidth = dc.GetTextExtent( _T(" ") ).cx;
		dc.SelectObject( pOldFont );
		dc.DeleteDC();
	}

	CString strInformation;
	BOOL res = FALSE;

	switch( pThread->m_command )
	{
	case ID_PROCESSES_INFO:
		{
			res = GetProcessInformation( strInformation );
		}
		break;
	}

	strInformation.Replace( _T("\n"), _T("\r\n") );
	m_wndInfo.SetWindowText( strInformation );
	m_wndInfo.LineScroll( y, x/iCharWidth );
}

/////////////////////////////////////////////////////////////////////////////

struct FTIME
{
	FTIME()
	{
		li.QuadPart = 0;
	}

	FTIME( const FILETIME& ft )
	{
		li.LowPart = ft.dwLowDateTime;
		li.HighPart = ft.dwHighDateTime;
	}

	FTIME( const LONGLONG& l64 )
	{
		li.QuadPart = l64;
	}

	FTIME( const LARGE_INTEGER& li2 )
	{
		li.QuadPart = li2.QuadPart;
	}

	operator FILETIME()
	{
		FILETIME ft;
		ft.dwLowDateTime = li.LowPart;
		ft.dwHighDateTime = li.HighPart;
		return ft;
	}

	operator LONGLONG()
	{
		return li.QuadPart;
	}

	operator LARGE_INTEGER()
	{
		return li;
	}

	LARGE_INTEGER li;
};

CString GetPeriod( LONGLONG l64 ) // IN: FILETIME
{
	CString s;
	LONGLONG milliseconds = l64/10000;
	DWORD hours = (DWORD) milliseconds / (3600 * 1000);
	DWORD min = (DWORD) (milliseconds / (60 * 1000)) % 60;
	DWORD sec = (DWORD) (milliseconds / (1000)) % 60;
	DWORD ms = (DWORD) milliseconds % 1000;
	s.Format( _T("%d:%02d:%02d.%03d"), hours, min, sec, ms );
	return s;
}

/////////////////////////////////////////////////////////////////////////////

BOOL CInformationDlg::GetProcessInformation( CString& info )
{
	CInformationDlgThread* pThread = (CInformationDlgThread*)AfxGetThread();
	info.Empty();

	// Get teh process list
	SystemProcessInformation spi( pThread->m_processID, TRUE, TRUE );

	DWORD pID;
	SystemProcessInformation::PROCESS_INFO pi;
	ZeroMemory( &pi, sizeof(pi) );

	// Iterating through the processes and get the module list
	for ( POSITION pos = spi.m_ProcessInfos.GetStartPosition(); pos != NULL; )
	{
		spi.m_ProcessInfos.GetNextAssoc( pos, pID, pi );
		break; // I hope there is only one process with PID == m_processId 8-)
	}

	CString d;
	TCHAR szBuf[MAX_PATH] = _T("");
	CTime t;

	SYSTEMTIME st;
	GetLocalTime( &st );

	FILETIME ft;
	SystemTimeToFileTime( &st, &ft );

	FILETIME ft2;
	GetSystemTimeAsFileTime( &ft2 );

	FTIME	time1 = ft;
	FTIME	time2 = ft2;

	FTIME	ftCreation;
	FTIME	ftKernel;
	FTIME	ftUser;

#pragma message (WARNING "Lots of hardcoded strings!")

	d.Format( _T("Process \"%ls\" (PID = %d) information:\n"), pi.spi.ProcessName.Buffer, pi.processId );
	info += d;
	d.Format( _T("=================================================\n\n") );
	info += d;

	d.Format( _T("Exe image name:\t\t\t\"%s\"\n"), pi.szExe );
	info += d;

	SystemMemoryMapInformation::FileFromAddress( pThread->m_processID, NULL, szBuf, SIZEOF_ARRAY(szBuf) );
	d.Format( _T("Exe file:\t\t\t\t\"%s\"\n"), szBuf );
	info += d;

	GetProcessExecutableName( pi.spi.InheritedFromProcessId, szBuf, SIZEOF_ARRAY(szBuf) );
	d.Format( _T("Parent process:\t\t\tPID = %d, \"%s\"\n"), pi.spi.InheritedFromProcessId, szBuf );
	info += d;

	d.Format( _T("Base priority:\t\t\t%d; priority boost: %s\n"), pi.spi.BasePriority,
		(pi.bDisablePriorityBoost ? _T("Disabled") : _T("Enabled") ) );
	info += d;

	d.Format( _T("CPU affinity mask:\t\t0x%X; system CPU affinity mask: 0x%X\n"),
		pi.dwProcessAffinity, pi.dwSystemAffinity );
	info += d;

	d.Format( _T("Image version:\t\t\t%d.%d\n"),
		HIWORD(pi.dwVersion), LOWORD(pi.dwVersion) );
	info += d;

	d.Format( _T("Working set:\t\t\t%d, min = %d, max = %d\n"),
		pi.pmc.WorkingSetSize, pi.minWorkSet, pi.maxWorkSet );
	info += d;

//////////////////////////////////////////////////////////////////////////
/*
	ftCreation = pi.spi.CreateTime;
	ftKernel = pi.spi.KernelTime.QuadPart * 10;
	ftUser = pi.spi.UserTime.QuadPart * 10;

	if( ftCreation != 0 )
	{
		t = (FILETIME)ftCreation;
		d.Format( _T("Process create time:\t%s\n"), t.Format( _T("%#c") ) );
		info += d;

		d.Format( _T("Process age:\t\t\t%s\n"), GetPeriod(time2 - ftCreation) );
		info += d;
	}

	d.Format( _T("Process kernel time:\t%s\n"), GetPeriod(ftKernel) );
	info += d;

	d.Format( _T("Process user time:\t\t%s\n"), GetPeriod(ftUser) );
	info += d;

	d.Format( _T("Process kernel + user time:\t%s\n"), GetPeriod(ftKernel + ftUser) );
	info += d;
//*/
//////////////////////////////////////////////////////////////////////////

	ftCreation = pi.ftCreation;
	ftKernel = pi.ftKernel;
	ftKernel = ftKernel * 10;
	ftUser = pi.ftUser;
	ftUser = ftUser * 10;

	if( ftCreation != 0 )
	{
		t = (FILETIME)ftCreation;
		d.Format( _T("Process create time:\t%s\n"), t.Format( _T("%#c") ) );
		info += d;

		d.Format( _T("Process age:\t\t\t%s\n"), GetPeriod(time2 - ftCreation) );
		info += d;
	}

	d.Format( _T("Process kernel time:\t%s\n"), GetPeriod(ftKernel) );
	info += d;

	d.Format( _T("Process user time:\t\t%s\n"), GetPeriod(ftUser) );
	info += d;

	d.Format( _T("Process kernel + user time:\t%s\n"), GetPeriod(ftKernel + ftUser) );
	info += d;

//////////////////////////////////////////////////////////////////////////

	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////

void CInformationDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		if( cxIcon == 16 && cyIcon == 16 )
		{
			dc.DrawIcon( x, y, theApp.hMainIconSmall );
		}
		else
		{
			dc.DrawIcon( x, y, theApp.hMainIconSmall );
		}
	}
	else
	{
		CDialog::OnPaint();
	}
}

/////////////////////////////////////////////////////////////////////////////

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