Click here to Skip to main content
15,897,291 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 598.7K   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"

#include "LoadDll.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( this );
	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( !IsIconic() )
	{
		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!

	bool bAlwaysOnTop = theApp.IsTaskManagerWindowTopMost();
	if( bAlwaysOnTop )
	{
		::SetWindowPos( *this, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE );
	}

	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 );
	SetWindowPos( NULL, 0, 0, 700, 600, SWP_NOMOVE | SWP_NOZORDER );

	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;
}

struct FLAG_INFO
{
	int iFlag;
	LPCTSTR szFlagName;
	LPCTSTR szDescription;
};

#define FLAG(x, d)	{ x, _T(#x), d },
#define NULL_FLAG	{ 0, NULL, NULL }

FLAG_INFO flagsServiceTypeFlags[] =
{
	FLAG( SERVICE_FILE_SYSTEM_DRIVER, _T("The service is a file system driver.") )
	FLAG( SERVICE_KERNEL_DRIVER, _T("The service is a device driver.") )
	FLAG( SERVICE_WIN32_OWN_PROCESS, _T("The service runs in its own process.") )
	FLAG( SERVICE_WIN32_SHARE_PROCESS, _T("The service shares a process with other services.") )
	FLAG( SERVICE_INTERACTIVE_PROCESS, _T("The service can interact with the desktop.") )
	NULL_FLAG
};

FLAG_INFO flagsServiceStatusValues[] =
{
	FLAG( SERVICE_STOPPED, _T("The service is not running.") )
	FLAG( SERVICE_START_PENDING, _T("The service is starting.") )
	FLAG( SERVICE_STOP_PENDING, _T("The service is stopping.") )
	FLAG( SERVICE_RUNNING, _T("The service is running.") )
	FLAG( SERVICE_CONTINUE_PENDING, _T("The service continue is pending.") )
	FLAG( SERVICE_PAUSE_PENDING, _T("The service pause is pending.") )
	FLAG( SERVICE_PAUSED, _T("The service is paused.") )
	NULL_FLAG
};

FLAG_INFO flagsServiceAcceptFlags[] =
{
	FLAG( SERVICE_ACCEPT_NETBINDCHANGE, _T("The service is a network component that can accept changes in its binding without being stopped and restarted.") )
	FLAG( SERVICE_ACCEPT_PARAMCHANGE, _T("The service can reread its startup parameters without being stopped and restarted.") )
	FLAG( SERVICE_ACCEPT_PAUSE_CONTINUE, _T("The service can be paused and continued.") )
	FLAG( SERVICE_ACCEPT_SHUTDOWN, _T("The service is notified when system shutdown occurs.") )
	FLAG( SERVICE_ACCEPT_STOP, _T("The service can be stopped.") )
	FLAG( SERVICE_ACCEPT_HARDWAREPROFILECHANGE, _T("The service is notified when the computer's hardware profile has changed.") )
	FLAG( SERVICE_ACCEPT_POWEREVENT, _T("The service is notified when the computer's power status has changed.") )
	FLAG( SERVICE_ACCEPT_SESSIONCHANGE, _T("The service is notified when the computer's session status has changed.") )
	NULL_FLAG
};


FLAG_INFO flagsServiceFlags[] =
{
	FLAG( 0, _T("The service is running in a process that is not a system process, or it is not running.") )
	FLAG( SERVICE_RUNS_IN_SYSTEM_PROCESS, _T("The service runs in a system process that must always be running.") )
	NULL_FLAG
};

tstring DecodeFlags( DWORD x, FLAG_INFO* pInfo, bool bMultipleFlags, bool bAdvanced, LPCTSTR szPrefix )
{
	DWORD Value = x;
	std::vector<FLAG_INFO*> arrFlags;
	for( FLAG_INFO* p = pInfo; p->szFlagName != NULL; p++ )
	{
		DWORD flag = p->iFlag;
		if( bMultipleFlags )
		{
			if( flag == 0 )
			{
				if( x == 0 )
				{
					arrFlags.push_back( p );
				}
			}
			else if( 0 != (flag & Value) )
			{
				Value &= ~flag;
				arrFlags.push_back( p );
			}
		}
		else
		{
			if( flag == Value )
			{
				Value = 0;
				arrFlags.push_back( p );
			}
		}
	}

	tstring sUnknown;
	tstring sUnknownName;
	if( Value != 0 )
	{
		TCHAR buf[100] = _T("");
		_stprintf( buf, _T("0x%08X"), Value );
		sUnknown = buf;
		sUnknownName = _T("Unknown_") + sUnknown;
	}
	FLAG_INFO fUnknown = { 0, sUnknown.c_str(), sUnknownName.c_str() };
	if( Value != 0 )
	{
		arrFlags.push_back( &fUnknown );
	}

	FLAG_INFO fEmpty = { 0, _T("<empty>"), _T("<empty value>")  };
	if( arrFlags.size() == 0 && x==0 )
	{
		arrFlags.push_back( &fEmpty );
	}

	tstring s;
	for( size_t i=0; i<arrFlags.size(); i++ )
	{
		FLAG_INFO& info = *arrFlags[i];

		if( bAdvanced )
		{
			TCHAR buf[100] = _T("");
			_stprintf( buf, _T("%-25s"), info.szFlagName );

			s += szPrefix;
			s += buf;
			s += _T(" - ");
			s += info.szDescription;
			s += _T("\n");
		}
		else
		{
			if( s.length() > 0 )
			{
				s += _T(" | ");
			}
			s += info.szFlagName;
		}
	}

	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;

	tstring sCommandLine;

	{
		DWORD dwFuncRetVal = FALSE;
		LONG LastError = 0;

		DWORD dwSpecial = 0;

		using namespace RemoteExecute;
		DWORD dwRet = LoadDllForRemoteThread( pi.processId,
			LOAD_LIBRARY, FREE_LIBRARY, GET_COMMAND_LINE,
			_T("kernel32.dll"), "GetCommandLine" FUNC_SUFFIX,
			&dwFuncRetVal, &dwSpecial, &LastError,
			DONT_RETURN_REMOTE_API_ERRORS,
			ZeroArguments, NoArguments );

		BOOL bOK = dwRet == 0;

		if( bOK && dwFuncRetVal != 0 )
		{
			TCHAR* pCmdLine = (TCHAR*) dwFuncRetVal;
			sCommandLine = pCmdLine;
			FreeSpecialBuffer( dwFuncRetVal );
		}
	}

//#pragma  warning (push, 3)
//#pragma  warning (disable: 4786)
	std::vector<tstring> arrEnvironment;
//#pragma  warning (pop)
	{
		DWORD dwFuncRetVal = FALSE;
		LONG LastError = 0;

		DWORD dwSpecial = 0;

		using namespace RemoteExecute;
		DWORD dwRet = LoadDllForRemoteThread( pi.processId,
			LOAD_LIBRARY, FREE_LIBRARY, GET_ENVIRONMENT,
			_T("kernel32.dll"), "GetEnvironmentStrings" FUNC_SUFFIX_ALT,
			&dwFuncRetVal, &dwSpecial, &LastError,
			DONT_RETURN_REMOTE_API_ERRORS,
			ZeroArguments, NoArguments );

		BOOL bOK = dwRet == 0;

		if( bOK && dwFuncRetVal != 0 )
		{
			TCHAR* pEnv = (TCHAR*) dwFuncRetVal;

			while( *pEnv )
			{
				tstring s = pEnv;
				arrEnvironment.push_back( s );
				pEnv += s.length() + 1;
			}

			FreeSpecialBuffer( dwFuncRetVal );
		}
	}

	std::vector<MY_SERVICE_INFO> arrServices;
	
	DWORD dwSCManagerProcessId = IS_PID_SYSTEM( pi.processId ) ? 0 : pi.processId;

	// Enumerate all Windows Services running in the current process:
	if( IAdvapi32::EnumServicesStatusEx != NULL )
	{
		SC_HANDLE hSCManager = OpenSCManager( NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE );
		if( hSCManager != NULL )
		{
			const DWORD dwServiceType = SERVICE_WIN32 | SERVICE_DRIVER;
			const DWORD dwServiceState = SERVICE_ACTIVE; // SERVICE_STATE_ALL;
			DWORD dwBytesNeeded = 0;
			DWORD dwServiceReturned = 0;
			DWORD dwResumeHandle = 0;
			BYTE buf[64*1024];
			const DWORD dwSize = sizeof(buf);
			IAdvapi32::LPENUM_SERVICE_STATUS_PROCESS pEnum = (IAdvapi32::LPENUM_SERVICE_STATUS_PROCESS) &buf;
			BOOL res;
			LONG err;
			DWORD i;

			while(TRUE)
			{
				res = IAdvapi32::EnumServicesStatusEx( hSCManager,
					IAdvapi32::SC_ENUM_PROCESS_INFO,
					dwServiceType, dwServiceState, buf, dwSize,
					&dwBytesNeeded, &dwServiceReturned, &dwResumeHandle, NULL );
				err = GetLastError();

				if( res || ( !res && err == ERROR_MORE_DATA ) )
				{
					for( i=0; i<dwServiceReturned; i++ )
					{
						IAdvapi32::ENUM_SERVICE_STATUS_PROCESS& info = pEnum[i];
						if( info.ServiceStatusProcess.dwProcessId == dwSCManagerProcessId )
						{
							MY_SERVICE_INFO info2;
							info2.sName = info.lpServiceName;
							info2.sDisplay = info.lpDisplayName;
							info2.ServiceStatusProcess = info.ServiceStatusProcess;
							arrServices.push_back( info2 );
						}
					}
				}

				if( !res && err == ERROR_MORE_DATA )
				{
					continue;
				}

				break;
			}

			CloseServiceHandle( hSCManager );
			hSCManager = NULL;
		}
		else
		{
			TRACE( _T("TaskManagerEx: Can't open service manager! (err - %d)\n"), GetLastError() );
		}
	}
	else
	{
		TRACE( _T("TaskManagerEx: IAdvapi32::EnumServicesStatusEx is not ready!\n") );
	}

//#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) );
	if( 0 != _tcsicmp( szBuf, pi.szExe ) )
	{
		d.Format( _T("Exe file (ORIGINAL!!!):\t\"%s\"\n"), szBuf );
		info += d;
	}

	if( sCommandLine.length() > 0 )
	{
		d.Format( _T("Command line:\t\t\t%s\n"), sCommandLine.c_str() );
		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;

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

	d.Format( _T("==================================\n") );
	info += d;

	if( arrServices.size() > 0 )
	{
		d.Format( _T("Services:\n") );
		info += d;

		for( size_t i=0; i<arrServices.size(); i++ )
		{
			MY_SERVICE_INFO& info2 = arrServices[i];
			IAdvapi32::SERVICE_STATUS_PROCESS& ssp = info2.ServiceStatusProcess;
			TCHAR szBuf[200] = _T("");

			_sntprintf( szBuf, SIZEOF_ARRAY(szBuf), _T("%s (%s):"),
				info2.sName.c_str(), info2.sDisplay.c_str() );

			d.Format( _T("\t\t%-30s type = %s; state = %s; accepted = %s; flags = %s;\n"),
				szBuf,
				DecodeFlags( ssp.dwServiceType, flagsServiceTypeFlags, true, false, NULL ).c_str(),
				DecodeFlags( ssp.dwCurrentState, flagsServiceStatusValues, true, false, NULL ).c_str(),
				DecodeFlags( ssp.dwControlsAccepted, flagsServiceAcceptFlags, true, false, NULL ).c_str(),
				DecodeFlags( ssp.dwServiceFlags, flagsServiceFlags, true, false, NULL ).c_str()
				);

			info += d;
		}
	}
	else
	{
		d.Format( _T("Services:\t\t\t\tThere are no services in this process!\n") );
		info += d;
	}

	if( arrServices.size() > 0 )
	{
		d.Format( _T("==================================\n") );
		info += d;
		d.Format( _T("Services (full information):\n") );
		info += d;

		for( size_t i=0; i<arrServices.size(); i++ )
		{
			MY_SERVICE_INFO& info2 = arrServices[i];
			IAdvapi32::SERVICE_STATUS_PROCESS& ssp = info2.ServiceStatusProcess;
			TCHAR szBuf[200] = _T("");

			_sntprintf( szBuf, SIZEOF_ARRAY(szBuf), _T("%s (%s):"),
				info2.sName.c_str(), info2.sDisplay.c_str() );

			//LPCTSTR szPref = _T("\t");

			d.Format( _T("Service: \t%-30s\n%s%s%s%s\n"),
				szBuf,
				DecodeFlags( ssp.dwServiceType, flagsServiceTypeFlags, true, true, _T("type:\t") ).c_str(),
				DecodeFlags( ssp.dwCurrentState, flagsServiceStatusValues, true, true, _T("status:\t") ).c_str(),
				DecodeFlags( ssp.dwControlsAccepted, flagsServiceAcceptFlags, true, true, _T("accept:\t") ).c_str(),
				DecodeFlags( ssp.dwServiceFlags, flagsServiceFlags, true, true, _T("flags:\t") ).c_str()
				);

			info += d;
		}
	}

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

	if( arrEnvironment.size() > 0 )
	{
		d.Format( _T("==================================\n") );
		info += d;
		d.Format( _T("Process Environment:\n") );
		info += d;

		for( size_t i=0; i<arrEnvironment.size(); i++ )
		{
			tstring sEnv = arrEnvironment[i];
			d.Format( _T("\t%s\n"), sEnv.c_str() );
			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