Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1587 lines
49 KiB

// *********************************************************************************
//
// Copyright (c) Microsoft Corporation
//
// Module Name:
//
// ShowTasks.cpp
//
// Abstract:
//
// This module displays the tasks that were retrieved
//
// Author:
//
// Sunil G.V.N. Murali ([email protected]) 25-Nov-2000
//
// Revision History:
//
// Sunil G.V.N. Murali ([email protected]) 25-Nov-2000 : Created It.
//
// *********************************************************************************
#include "pch.h"
#include "wmi.h"
#include "TaskList.h"
//
// define(s) / constants
//
#define MAX_TIMEOUT_RETRIES 300
#define MAX_ENUM_TASKS 5
#define MAX_ENUM_SERVICES 10
#define MAX_ENUM_MODULES 5
#define FMT_KILOBYTE GetResString( IDS_FMT_KILOBYTE )
#define MAX_COL_FORMAT 65
#define MAX_COL_HEADER 256
// structure signatures
#define SIGNATURE_MODULES 9
//
// typedefs
//
typedef struct _tagModulesInfo
{
DWORD dwSignature;
DWORD dwLength;
LPCWSTR pwszModule;
TARRAY arrModules;
} TMODULESINFO, *PTMODULESINFO;
//
// function prototypes
//
#ifndef _WIN64
BOOL EnumLoadedModulesProc( LPSTR lpszModuleName, ULONG ulModuleBase, ULONG ulModuleSize, PVOID pUserData );
#else
BOOL EnumLoadedModulesProc64( LPSTR lpszModuleName, DWORD64 ulModuleBase, ULONG ulModuleSize, PVOID pUserData );
#endif
DWORD
CTaskList::Show(
void
)
/*++
Routine Description:
show the tasks running
Arguments:
NONE
Return Value:
NONE
--*/
{
// local variables
HRESULT hr;
DWORD dwCount = 0;
DWORD dwFormat = 0;
DWORD dwFilters = 0;
DWORD dwTimeOuts = 0;
ULONG ulReturned = 0;
BOOL bCanExit = FALSE;
IWbemClassObject* pObjects[ MAX_ENUM_TASKS ];
// init the objects to NULL's
for( DWORD dw = 0; dw < MAX_ENUM_TASKS; dw++ )
{
pObjects[ dw ] = NULL;
}
// copy the format that has to be displayed into local memory
bCanExit = FALSE;
dwFormat = m_dwFormat;
dwFilters = DynArrayGetCount( m_arrFiltersEx );
// prepare the columns structure to display
PrepareColumns();
// clear the error code ... if any
SetLastError( ( DWORD )NO_ERROR );
try
{
// dynamically decide whether to hide or show the window title and status in verbose mode
if ( FALSE == m_bLocalSystem )
{
if ( TRUE == m_bVerbose )
{
( m_pColumns + CI_STATUS )->dwFlags |= SR_HIDECOLUMN;
( m_pColumns + CI_WINDOWTITLE )->dwFlags |= SR_HIDECOLUMN;
}
// check if we need to display the warning message or not
if ( TRUE == m_bRemoteWarning )
{
ShowMessage( stderr, WARNING_FILTERNOTSUPPORTED );
}
}
// loop thru the process instances
dwTimeOuts = 0;
do
{
// get the object ... wait only for 1 sec at one time ...
hr = m_pEnumObjects->Next( 1000, MAX_ENUM_TASKS, pObjects, &ulReturned );
if ( (HRESULT) WBEM_S_FALSE == hr )
{
// we've reached the end of enumeration .. set the flag
bCanExit = TRUE;
}
else
{
if ( (HRESULT) WBEM_S_TIMEDOUT == hr )
{
// update the timeouts occured
dwTimeOuts++;
// check if max. retries have reached ... if yes better stop
if ( dwTimeOuts > MAX_TIMEOUT_RETRIES )
{
for( ULONG ul = 0; ul < MAX_ENUM_TASKS; ul++ )
{
// we need to release the wmi object
SAFE_RELEASE( pObjects[ ul ] );
}
// time out error
SetLastError( ( DWORD )ERROR_TIMEOUT );
SaveLastError();
return 0;
}
// still we can do more tries ...
continue;
}
else
{
if ( FAILED( hr ) )
{
// some error has occured ... oooppps
WMISaveError( hr );
SetLastError( ( DWORD )STG_E_UNKNOWN );
return 0;
}
}
}
// reset the timeout counter
dwTimeOuts = 0;
// loop thru the objects and save the info
for( ULONG ul = 0; ul < ulReturned; ul++ )
{
// retrive and save data
LONG lIndex = DynArrayAppendRow( m_arrTasks, MAX_TASKSINFO );
SaveInformation( lIndex, pObjects[ ul ] );
// we need to release the wmi object
SAFE_RELEASE( pObjects[ ul ] );
}
// filter the results .. before doing first if filters do exist or not
if ( 0 != dwFilters )
{
FilterResults( MAX_FILTERS, m_pfilterConfigs, m_arrTasks, m_arrFiltersEx );
}
// now show the tasks ... if exists
if ( 0 != DynArrayGetCount( m_arrTasks ) )
{
// if the output is not being displayed first time,
// print one blank line in between ONLY FOR LIST FORMAT
if ( ( 0 != dwCount ) && ((dwFormat & SR_FORMAT_MASK) == SR_FORMAT_LIST) )
{
ShowMessage( stdout, L"\n" );
}
else
{
if ( ( 0 == dwCount ) && ((dwFormat & SR_FORMAT_MASK) != SR_FORMAT_CSV) )
{
// output is being displayed for the first time
ShowMessage( stdout, L"\n" );
}
}
// show the tasks
ShowResults( MAX_COLUMNS, m_pColumns, dwFormat, m_arrTasks );
// clear the contents and reset
dwCount += DynArrayGetCount( m_arrTasks ); // update count
DynArrayRemoveAll( m_arrTasks );
// to be on safe side, set the apply no heade flag to the format info
dwFormat |= SR_NOHEADER;
}
} while ( FALSE == bCanExit );
}
catch( ... )
{
SetLastError( ( DWORD )E_OUTOFMEMORY );
SaveLastError();
return 0;
}
// clear the error code ... if any
// NOTE: BELOW STATEMENT IS THE ONLY ANSWER FOR KNOWING THAT ANY PROCESS
// ARE OBTAINED OR NOT FOR DELETION.
SetLastError( ( DWORD )NO_ERROR );
// return the no. of tasks that were shown
return dwCount;
}
BOOL
CTaskList::SaveInformation(
IN LONG lIndex,
IN IWbemClassObject* pWmiObject
)
/*++
Routine Description:
Store infomration obtained in dynaimc array.
Arguments:
[ in ] lIndex : Contains index value of dynamic array.
[ in ] pWmiObject : Contains interface pointer.
Return Value:
TRUE if successful else FALSE.
--*/
{
// local variables
CHString str;
try
{
// object path
PropertyGet( pWmiObject, WIN32_PROCESS_SYSPROPERTY_PATH, str );
DynArraySetString2( m_arrTasks, lIndex, TASK_OBJPATH, str, 0 );
// process id
PropertyGet( pWmiObject, WIN32_PROCESS_PROPERTY_PROCESSID, m_dwProcessId );
DynArraySetDWORD2( m_arrTasks, lIndex, TASK_PID, m_dwProcessId );
// host name
PropertyGet( pWmiObject, WIN32_PROCESS_PROPERTY_COMPUTER, str );
DynArraySetString2( m_arrTasks, lIndex, TASK_HOSTNAME, str, 0 );
// image name
PropertyGet( pWmiObject, WIN32_PROCESS_PROPERTY_IMAGENAME, m_strImageName );
DynArraySetString2( m_arrTasks, lIndex, TASK_IMAGENAME, m_strImageName, 0 );
// cpu Time
SetCPUTime( lIndex, pWmiObject );
// session id and session name
SetSession( lIndex, pWmiObject );
// mem usage
SetMemUsage( lIndex, pWmiObject );
// user context
SetUserContext( lIndex, pWmiObject );
// window title and process / application state
SetWindowTitle( lIndex );
// services
SetServicesInfo( lIndex );
// modules
SetModulesInfo( lIndex );
}
catch( CHeap_Exception )
{
SetLastError( ( DWORD )E_OUTOFMEMORY );
SaveLastError();
return FALSE;
}
// return
return TRUE;
}
VOID
CTaskList::SetUserContext(
IN LONG lIndex,
IN IWbemClassObject* pWmiObject
)
/*++
Routine Description:
Store username property of a process in dynaimc array.
Arguments:
[ in ] lIndex : Contains index value of dynamic array.
[ in ] pWmiObject : Contains interface pointer.
Return Value:
VOID
--*/
{
// local variables
HRESULT hr;
CHString str;
CHString strPath;
CHString strDomain;
CHString strUserName;
BOOL bResult = FALSE;
IWbemClassObject* pOutParams = NULL;
// set the default value
DynArraySetString2( m_arrTasks, lIndex, TASK_USERNAME, V_NOT_AVAILABLE, 0 );
// check if user name has to be retrieved or not
if ( FALSE == m_bNeedUserContextInfo )
{
return;
}
//
// for getting the user first we will try with API
// it at all API fails, we will try to get the same information from WMI
//
try
{
// get the user name
str = V_NOT_AVAILABLE;
if ( TRUE == LoadUserNameFromWinsta( strDomain, strUserName ) )
{
// format the user name
str.Format( L"%s\\%s", strDomain, strUserName );
}
else
{
// user name has to be retrieved - get the path of the current object
bResult = PropertyGet( pWmiObject, WIN32_PROCESS_SYSPROPERTY_PATH, strPath );
if ( ( FALSE == bResult ) ||
( 0 == strPath.GetLength() ) )
{
return;
}
// execute the GetOwner method and get the user name
// under which the current process is executing
hr = m_pWbemServices->ExecMethod( _bstr_t( strPath ),
_bstr_t( WIN32_PROCESS_METHOD_GETOWNER ), 0, NULL, NULL, &pOutParams, NULL );
if ( FAILED( hr ) )
{
return;
}
// get the domain and user values from out params object
// NOTE: do not check the results
PropertyGet( pOutParams, GETOWNER_RETURNVALUE_DOMAIN, strDomain, L"" );
PropertyGet( pOutParams, GETOWNER_RETURNVALUE_USER, strUserName, L"" );
// get the value
str = V_NOT_AVAILABLE;
if ( 0 != strDomain.GetLength() )
{
str.Format( L"%s\\%s", strDomain, strUserName );
}
else
{
if ( 0 != strUserName.GetLength() )
{
str = strUserName;
}
}
}
// the formatted username might contain the UPN format user name
// so ... remove that part
if ( -1 != str.Find( L"@" ) )
{
// sub-local
LONG lPos = 0;
CHString strTemp;
// get the position
lPos = str.Find( L"@" );
strTemp = str.Left( lPos );
str = strTemp;
}
// save the info
DynArraySetString2( m_arrTasks, lIndex, TASK_USERNAME, str, 0 );
}
catch( CHeap_Exception )
{
SAFE_RELEASE( pOutParams );
SetLastError( ( DWORD )E_OUTOFMEMORY );
SaveLastError();
}
SAFE_RELEASE( pOutParams );
return;
}
VOID
CTaskList::SetCPUTime(
IN LONG lIndex,
IN IWbemClassObject* pWmiObject
)
/*++
Routine Description:
Store CPUTIME property of a process in dynaimc array.
Arguments:
[ in ] lIndex : Contains index value of dynamic array.
[ in ] pWmiObject : Contains interface pointer.
Return Value:
VOID
--*/
{
// local variables
CHString str;
BOOL bResult = FALSE;
ULONGLONG ullCPUTime = 0;
ULONGLONG ullUserTime = 0;
ULONGLONG ullKernelTime = 0;
try
{
// get the KernelModeTime value
bResult = PropertyGet( pWmiObject, WIN32_PROCESS_PROPERTY_KERNELMODETIME, ullKernelTime );
// get the user mode time
bResult = PropertyGet( pWmiObject, WIN32_PROCESS_PROPERTY_USERMODETIME, ullUserTime );
// calculate the CPU time
ullCPUTime = ullUserTime + ullKernelTime;
// now convert the long time into hours format
TIME_FIELDS time;
SecureZeroMemory( &time, sizeof( TIME_FIELDS ) );
RtlTimeToElapsedTimeFields ( (LARGE_INTEGER* ) &ullCPUTime, &time );
// convert the days into hours
time.Hour = static_cast<CSHORT>( time.Hour + static_cast<SHORT>( time.Day * 24 ) );
// prepare into time format ( user locale specific time seperator )
str.Format( L"%d%s%02d%s%02d",
time.Hour, m_strTimeSep, time.Minute, m_strTimeSep, time.Second );
// save the info
DynArraySetString2( m_arrTasks, lIndex, TASK_CPUTIME, str, 0 );
}
catch( CHeap_Exception )
{
SetLastError( ( DWORD )E_OUTOFMEMORY );
SaveLastError();
}
return;
}
VOID
CTaskList::SetWindowTitle(
IN LONG lIndex
)
/*++
Routine Description:
Store 'Window Title' property of a process in dynaimc array.
Arguments:
[ in ] lIndex : Contains index value of dynamic array.
Return Value:
VOID
--*/
{
// local variables
LONG lTemp = 0;
BOOL bHung = FALSE;
LPCWSTR pwszTemp = NULL;
CHString strTitle;
CHString strState;
try
{
// Initialize status value.
strState = VALUE_UNKNOWN ;
// get the window details ... window station, desktop, window title
// NOTE: This will work only for local system
lTemp = DynArrayFindDWORDEx( m_arrWindowTitles, CTaskList::twiProcessId, m_dwProcessId );
if ( -1 != lTemp )
{
// window title
pwszTemp = DynArrayItemAsString2( m_arrWindowTitles, lTemp, CTaskList::twiTitle );
if ( NULL != pwszTemp )
{
strTitle = pwszTemp;
}
// application / process state
bHung = DynArrayItemAsBOOL2( m_arrWindowTitles, lTemp, CTaskList::twiHungInfo );
strState = ( FALSE == bHung ) ? VALUE_RUNNING : VALUE_NOTRESPONDING;
}
// save the info
DynArraySetString2( m_arrTasks, lIndex, TASK_STATUS, strState, 0 );
DynArraySetString2( m_arrTasks, lIndex, TASK_WINDOWTITLE, strTitle, 0 );
}
catch( CHeap_Exception )
{
SetLastError( ( DWORD )E_OUTOFMEMORY );
SaveLastError();
}
return;
}
VOID
CTaskList::SetSession(
IN LONG lIndex,
IN IWbemClassObject* pWmiObject
)
/*++
Routine Description:
Store 'Session name' property of a process in dynaimc array.
Arguments:
[ in ] lIndex : Contains index value of dynamic array.
[ in ] pWmiObject : Contains interface pointer.
Return Value:
VOID
--*/
{
// local variables
CHString str;
DWORD dwSessionId = 0;
// set the default value
DynArraySetString2( m_arrTasks, lIndex, TASK_SESSION, V_NOT_AVAILABLE, 0 );
DynArraySetString2( m_arrTasks, lIndex, TASK_SESSIONNAME, L"", 0 );
try
{
// get the threads count for the process
if ( FALSE == PropertyGet( pWmiObject, WIN32_PROCESS_PROPERTY_SESSION, dwSessionId ) )
{
return;
}
// get the session id in string format
str.Format( L"%d", dwSessionId );
// save the id
DynArraySetString2( m_arrTasks, lIndex, TASK_SESSION, str, 0 );
// get the session name
if ( ( TRUE == m_bLocalSystem ) || ( ( FALSE == m_bLocalSystem ) && ( NULL != m_hServer ) ) )
{
// sub-local variables
LPWSTR pwsz = NULL;
// get the buffer
pwsz = str.GetBufferSetLength( WINSTATIONNAME_LENGTH + 1 );
// get the name for the session
if ( FALSE == WinStationNameFromLogonIdW( m_hServer, dwSessionId, pwsz ) )
{
return; // failed in getting the winstation/session name ... return
}
// release buffer
str.ReleaseBuffer();
// save the session name ... do this only if session name is not empty
if ( 0 != str.GetLength() )
{
DynArraySetString2( m_arrTasks, lIndex, TASK_SESSIONNAME, str, 0 );
}
}
}
catch( CHeap_Exception )
{
SetLastError( ( DWORD )E_OUTOFMEMORY );
SaveLastError();
}
return;
}
VOID
CTaskList::SetMemUsage(
IN LONG lIndex,
IN IWbemClassObject* pWmiObject
)
/*++
Routine Description:
Store 'Memory usage' property of a process in dynaimc array.
Arguments:
[ in ] lIndex : Contains index value of dynamic array.
[ in ] pWmiObject : Contains interface pointer.
Return Value:
VOID
--*/
{
// local variables
CHString str;
LONG lTemp = 0;
NUMBERFMTW nfmtw;
NTSTATUS ntstatus;
ULONGLONG ullMemUsage = 0;
LARGE_INTEGER liTemp = { 0, 0 };
CHAR szTempBuffer[ 33 ] = "\0";
WCHAR wszNumberStr[ 33 ] = L"\0";
try
{
// NOTE:
// ----
// The max. value of
// (2 ^ 64) - 1 = "18,446,744,073,709,600,000 K" (29 chars).
//
// so, the buffer size to store the number is fixed as 32 characters
// which is more than the 29 characters in actuals
// set the default value
DynArraySetString2( m_arrTasks, lIndex, TASK_MEMUSAGE, V_NOT_AVAILABLE, 0 );
// get the KernelModeTime value
if ( FALSE == PropertyGet( pWmiObject, WIN32_PROCESS_PROPERTY_MEMUSAGE, ullMemUsage ) )
{
return;
}
// convert the value into K Bytes
ullMemUsage /= 1024;
// now again convert the value from ULONGLONG to string and check the result
liTemp.QuadPart = ullMemUsage;
ntstatus = RtlLargeIntegerToChar( &liTemp, 10, SIZE_OF_ARRAY( szTempBuffer ), szTempBuffer );
if ( ! NT_SUCCESS( ntstatus ) )
{
return;
}
// now copy this info into UNICODE buffer
str = szTempBuffer;
//
// prepare to Format the number with commas according to locale conventions.
nfmtw.NumDigits = 0;
nfmtw.LeadingZero = 0;
nfmtw.NegativeOrder = 0;
nfmtw.Grouping = m_dwGroupSep;
nfmtw.lpDecimalSep = m_strGroupThousSep.GetBuffer( m_strGroupThousSep.GetLength() );
nfmtw.lpThousandSep = m_strGroupThousSep.GetBuffer( m_strGroupThousSep.GetLength() );
// convert the value
lTemp = GetNumberFormatW( LOCALE_USER_DEFAULT,
0, str, &nfmtw, wszNumberStr, SIZE_OF_ARRAY( wszNumberStr ) );
// get the session id in string format
str.Format( FMT_KILOBYTE, wszNumberStr );
// save the id
DynArraySetString2( m_arrTasks, lIndex, TASK_MEMUSAGE, str, 0 );
}
catch( CHeap_Exception )
{
SetLastError( ( DWORD )E_OUTOFMEMORY );
SaveLastError();
}
return;
}
VOID
CTaskList::SetServicesInfo(
IN LONG lIndex
)
/*++
Routine Description:
Store 'Service' property of a process in dynaimc array.
Arguments:
[ in ] lIndex : Contains index value of dynamic array.
Return Value:
VOID
--*/
{
// local variables
HRESULT hr;
CHString strQuery;
CHString strService;
ULONG ulReturned = 0;
BOOL bResult = FALSE;
BOOL bCanExit = FALSE;
TARRAY arrServices = NULL;
IEnumWbemClassObject* pEnumServices = NULL;
IWbemClassObject* pObjects[ MAX_ENUM_SERVICES ];
// check whether we need to gather services info or not .. if not skip
if ( FALSE == m_bNeedServicesInfo )
{
return;
}
// create array
arrServices = CreateDynamicArray();
if ( NULL == arrServices )
{
SetLastError( ( DWORD )E_OUTOFMEMORY );
SaveLastError();
return;
}
//
// for getting the services info first we will try with the one we got from API
// it at all API fails, we will try to get the same information from WMI
//
try
{
// check whether API returned services or not
if ( NULL != m_pServicesInfo )
{
// get the service names related to the current process
// identify all the services related to the current process ( based on the PID )
// and save the info
for ( DWORD dw = 0; dw < m_dwServicesCount; dw++ )
{
// compare the PID's
if ( m_dwProcessId == m_pServicesInfo[ dw ].ServiceStatusProcess.dwProcessId )
{
// this service is related with the current process ... store service name
DynArrayAppendString( arrServices, m_pServicesInfo[ dw ].lpServiceName, 0 );
}
}
}
else
{
try
{
// init the objects to NULL's
for( DWORD dw = 0; dw < MAX_ENUM_SERVICES; dw++ )
{
pObjects[ dw ] = NULL;
}
// prepare the query
strQuery.Format( WMI_SERVICE_QUERY, m_dwProcessId );
// execute the query
hr = m_pWbemServices->ExecQuery( _bstr_t( WMI_QUERY_TYPE ), _bstr_t( strQuery ),
WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, &pEnumServices );
// check the result
if ( FAILED( hr ) )
{
_com_issue_error( hr );
}
// set the security
hr = SetInterfaceSecurity( pEnumServices, m_pAuthIdentity );
if ( FAILED( hr ) )
{
_com_issue_error( hr );
}
// loop thru the service instances
do
{
// get the object ... wait
// NOTE: one-by-one
hr = pEnumServices->Next( WBEM_INFINITE, MAX_ENUM_SERVICES, pObjects, &ulReturned );
if ( (HRESULT) WBEM_S_FALSE == hr )
{
// we've reached the end of enumeration .. set the flag
bCanExit = TRUE;
}
else
{
if ( ( (HRESULT) WBEM_S_TIMEDOUT == hr ) || FAILED( hr ) )
{
//
// some error has occured ... oooppps
// exit from the loop
break;
}
}
// loop thru the objects and save the info
for( ULONG ul = 0; ul < ulReturned; ul++ )
{
// get the value of the property
bResult = PropertyGet( pObjects[ ul ], WIN32_SERVICE_PROPERTY_NAME, strService );
if ( TRUE == bResult )
{
DynArrayAppendString( arrServices, strService, 0 );
}
// release the interface
SAFE_RELEASE( pObjects[ ul ] );
}
} while ( FALSE == bCanExit );
}
catch( _com_error& e )
{
SAFE_RELEASE( pEnumServices );
// save the error
WMISaveError( e );
}
// release the objects to NULL's
for( DWORD dw = 0; dw < MAX_ENUM_SERVICES; dw++ )
{
// release all the objects
SAFE_RELEASE( pObjects[ dw ] );
}
// now release the enumeration object
SAFE_RELEASE( pEnumServices );
}
// save and return
DynArraySetEx2( m_arrTasks, lIndex, TASK_SERVICES, arrServices );
}
catch( CHeap_Exception )
{
SetLastError( ( DWORD )E_OUTOFMEMORY );
SaveLastError();
}
return;
}
BOOL
CTaskList::SetModulesInfo(
IN LONG lIndex
)
/*++
Routine Description:
Store 'Modules' property of a process in dynaimc array.
Arguments:
[ in ] lIndex : Contains index value of dynamic array.
Return Value:
TRUE if successful else FALSE.
--*/
{
// local variables
LONG lPos = 0;
BOOL bResult = FALSE;
TARRAY arrModules = NULL;
// check whether we need to get the modules or not
if ( FALSE == m_bNeedModulesInfo )
{
return TRUE;
}
// allocate for memory
arrModules = CreateDynamicArray();
if ( NULL == arrModules )
{
SetLastError( ( DWORD )E_OUTOFMEMORY );
SaveLastError();
return FALSE;
}
// the way we get the modules information is different for local remote
// so depending that call appropriate function
if ( ( TRUE == m_bLocalSystem ) && ( FALSE == m_bUseRemote ) )
{
// enumerate the modules for the current process
bResult = LoadModulesOnLocal( arrModules );
}
else
{
// identify the modules information for the current process ... remote system
bResult = GetModulesOnRemote( lIndex, arrModules );
}
// check the result
if ( TRUE == bResult )
{
try
{
// check if the modules list contains the imagename also. If yes remove that entry
lPos = DynArrayFindString( arrModules, m_strImageName, TRUE, 0 );
if ( -1 != lPos )
{
// remove the entry
DynArrayRemove( arrModules, lPos );
}
}
catch( CHeap_Exception )
{
SetLastError( ( DWORD )E_OUTOFMEMORY );
SaveLastError();
return FALSE;
}
}
// save the modules information to the array
// NOTE: irrespective of whether enumeration is success or not we will add the array
DynArraySetEx2( m_arrTasks, lIndex, TASK_MODULES, arrModules );
// return
return bResult;
}
BOOL
CTaskList::LoadModulesOnLocal(
IN OUT TARRAY arrModules
)
/*++
Routine Description:
Store 'Modules' property of a process in dynaimc array for local system.
Arguments:
[ in out ] arrModules : Contains dynamic array.
Return Value:
TRUE if successful else FALSE.
--*/
{
// local variables
LONG lPos = 0;
BOOL bResult = FALSE;
TMODULESINFO modules;
HANDLE hProcess = NULL;
// check the input values
if ( NULL == arrModules )
{
return FALSE;
}
// open the process handle
hProcess = OpenProcess( PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, m_dwProcessId );
if ( NULL == hProcess )
{
return FALSE; // failed in getting the process handle
}
// prepare the modules structure
SecureZeroMemory( &modules, sizeof( TMODULESINFO ) );
modules.dwSignature = SIGNATURE_MODULES;
modules.dwLength = 0;
modules.arrModules = arrModules;
try
{
modules.pwszModule = ((m_strModules.GetLength() != 0) ? (LPCWSTR) m_strModules : NULL);
if ( -1 != (lPos = m_strModules.Find( L"*" )) )
{
modules.dwLength = (DWORD) lPos;
modules.pwszModule = m_strModules;
}
}
catch( CHeap_Exception )
{
CloseHandle( hProcess );
hProcess = NULL;
SetLastError( ( DWORD )E_OUTOFMEMORY );
SaveLastError();
return FALSE;
}
#ifndef _WIN64
bResult = EnumerateLoadedModules( hProcess, EnumLoadedModulesProc, &modules );
#else
bResult = EnumerateLoadedModules64( hProcess, EnumLoadedModulesProc64, &modules );
#endif
// close the process handle .. we dont need this furthur
CloseHandle( hProcess );
hProcess = NULL;
// return
return bResult;
}
BOOL
CTaskList::GetModulesOnRemote(
IN LONG lIndex,
IN OUT TARRAY arrModules )
/*++
Routine Description:
Store 'Modules' property of a process in dynaimc array for remote system.
Arguments:
[ in ] lIndex : Contains index value of dynamic array.
[ in out ] arrModules : Contains dynamic array.
Return Value:
TRUE if successful else FALSE.
--*/
{
// local variables
LONG lPos = 0;
DWORD dwLength = 0;
DWORD dwOffset = 0;
DWORD dwInstance = 0;
PPERF_OBJECT_TYPE pot = NULL;
PPERF_OBJECT_TYPE potImages = NULL;
PPERF_INSTANCE_DEFINITION pidImages = NULL;
PPERF_COUNTER_BLOCK pcbImages = NULL;
PPERF_OBJECT_TYPE potAddressSpace = NULL;
PPERF_INSTANCE_DEFINITION pidAddressSpace = NULL;
PPERF_COUNTER_BLOCK pcbAddressSpace = NULL;
PPERF_COUNTER_DEFINITION pcd = NULL;
// check the input values
if ( NULL == arrModules )
{
return FALSE;
}
// check whether the performance object exists or not
// if doesn't exists, get the same using WMI
if ( NULL == m_pdb )
{
// invoke the WMI method
return GetModulesOnRemoteEx( lIndex, arrModules );
}
// get the perf object types
pot = (PPERF_OBJECT_TYPE) ( (LPBYTE) m_pdb + m_pdb->HeaderLength );
for( DWORD dw = 0; dw < m_pdb->NumObjectTypes; dw++ )
{
if ( 740 == pot->ObjectNameTitleIndex )
{
potImages = pot;
}
else
{
if ( 786 == pot->ObjectNameTitleIndex )
{
potAddressSpace = pot;
}
}
// move to the next object
dwOffset = pot->TotalByteLength;
if( 0 != dwOffset )
{
pot = ( (PPERF_OBJECT_TYPE) ((PBYTE) pot + dwOffset));
}
}
// check whether we got both the object types or not
if ( ( NULL == potImages ) || ( NULL == potAddressSpace ) )
{
return FALSE;
}
// find the offset of the process id in the address space object type
// get the first counter definition of address space object
pcd = (PPERF_COUNTER_DEFINITION) ( (LPBYTE) potAddressSpace + potAddressSpace->HeaderLength);
// loop thru the counters and find the offset
dwOffset = 0;
for( DWORD dw = 0; dw < potAddressSpace->NumCounters; dw++)
{
// 784 is the counter for process id
if ( 784 == pcd->CounterNameTitleIndex )
{
dwOffset = pcd->CounterOffset;
break;
}
// next counter
pcd = ( (PPERF_COUNTER_DEFINITION) ( (LPBYTE) pcd + pcd->ByteLength) );
}
// check whether we got the offset or not
// if not, we are unsuccessful
if ( 0 == dwOffset )
{
// set the error message
SetLastError( ( DWORD )ERROR_ACCESS_DENIED );
SaveLastError();
return FALSE;
}
// get the instances
pidImages = (PPERF_INSTANCE_DEFINITION) ( (LPBYTE) potImages + potImages->DefinitionLength );
pidAddressSpace = (PPERF_INSTANCE_DEFINITION) ( (LPBYTE) potAddressSpace + potAddressSpace->DefinitionLength );
// counter blocks
pcbImages = (PPERF_COUNTER_BLOCK) ( (LPBYTE) pidImages + pidImages->ByteLength );
pcbAddressSpace = (PPERF_COUNTER_BLOCK) ( (LPBYTE) pidAddressSpace + pidAddressSpace->ByteLength );
// find the instance number of the process which we are looking for
for( dwInstance = 0; dwInstance < (DWORD) potAddressSpace->NumInstances; dwInstance++ )
{
// sub-local variables
DWORD dwProcessId = 0;
// get the process id
dwProcessId = *((DWORD*) ( (LPBYTE) pcbAddressSpace + dwOffset ));
// now check if this is the process which we are looking for
if ( dwProcessId == m_dwProcessId )
{
break;
}
// continue looping thru other instances
pidAddressSpace = (PPERF_INSTANCE_DEFINITION) ( (LPBYTE) pcbAddressSpace + pcbAddressSpace->ByteLength );
pcbAddressSpace = (PPERF_COUNTER_BLOCK) ( (LPBYTE) pidAddressSpace + pidAddressSpace->ByteLength );
}
// check whether we got the instance or not
// if not, there are no modules for this process
if ( dwInstance == ( DWORD )potAddressSpace->NumInstances )
{
return TRUE;
}
//determine the length of the module name ..
dwLength = 0;
if ( -1 != (lPos = m_strModules.Find( L"*" )) )
{
dwLength = (DWORD) lPos;
}
// now based the parent instance, collect all the modules
for( DWORD dw = 0; (LONG) dw < potImages->NumInstances; dw++)
{
// check the parent object instance number
if ( pidImages->ParentObjectInstance == dwInstance )
{
try
{
// sub-local variables
CHString str;
LPWSTR pwszTemp;
// get the buffer
pwszTemp = str.GetBufferSetLength( pidImages->NameLength + 10 ); // +10 to be on safe side
if ( NULL == pwszTemp )
{
SetLastError( ( DWORD )E_OUTOFMEMORY );
SaveLastError();
return FALSE;
}
// get the instance name
StringCopy( pwszTemp, (LPWSTR) ( (LPBYTE) pidImages + pidImages->NameOffset ), pidImages->NameLength + 1 );
// release buffer
str.ReleaseBuffer();
// check whether this module needs to be added to the list
if ( ( 0 == m_strModules.GetLength() ) || ( 0 == StringCompare( str, m_strModules, TRUE, dwLength ) ) )
{
// add the info the userdata ( for us we will get that in the form of an array
lIndex = DynArrayAppendString( arrModules, str, 0 );
if ( -1 == lIndex )
{
// append is failed .. this could be because of lack of memory .. stop the enumeration
return FALSE;
}
}
}
catch( CHeap_Exception )
{
SetLastError( ( DWORD )E_OUTOFMEMORY );
SaveLastError();
return FALSE;
}
}
// continue looping thru other instances
pidImages = (PPERF_INSTANCE_DEFINITION) ( (LPBYTE) pcbImages + pcbImages->ByteLength );
pcbImages = (PPERF_COUNTER_BLOCK) ( (LPBYTE) pidImages + pidImages->ByteLength );
}
return TRUE;
}
BOOL
CTaskList::GetModulesOnRemoteEx(
IN LONG lIndex,
IN OUT TARRAY arrModules
)
/*++
Routine Description:
Store 'Modules' property of a process in dynaimc array for remote system.
Arguments:
[ in ] lIndex : Contains index value of dynamic array.
[ in out ] arrModules : Contains dynamic array.
Return Value:
TRUE if successful else FALSE.
--*/
{
// local variables
HRESULT hr;
LONG lPos = 0;
DWORD dwLength = 0;
CHString strQuery;
CHString strModule;
CHString strFileName;
CHString strExtension;
ULONG ulReturned = 0;
BOOL bResult = FALSE;
BOOL bCanExit = FALSE;
LPCWSTR pwszPath = NULL;
IEnumWbemClassObject* pEnumServices = NULL;
IWbemClassObject* pObjects[ MAX_ENUM_MODULES ];
// check the input values
if ( NULL == arrModules )
{
return FALSE;
}
// get the path of the object from the tasks array
pwszPath = DynArrayItemAsString2( m_arrTasks, lIndex, TASK_OBJPATH );
if ( NULL == pwszPath )
{
return FALSE;
}
try
{
//determine the length of the module name ..
dwLength = 0;
if ( -1 != (lPos = m_strModules.Find( L"*" )) )
{
dwLength = (DWORD) lPos;
}
// init the objects to NULL's
for( DWORD dw = 0; dw < MAX_ENUM_MODULES; dw++ )
{
pObjects[ dw ] = NULL;
}
// prepare the query
strQuery.Format( WMI_MODULES_QUERY, pwszPath );
// execute the query
hr = m_pWbemServices->ExecQuery( _bstr_t( WMI_QUERY_TYPE ), _bstr_t( strQuery ),
WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, &pEnumServices );
// check the result
if ( FAILED( hr ) )
{
_com_issue_error( hr );
}
// set the security
hr = SetInterfaceSecurity( pEnumServices, m_pAuthIdentity );
if ( FAILED( hr ) )
{
_com_issue_error( hr );
}
// loop thru the instances
do
{
// get the object ... wait
// NOTE: one-by-one
hr = pEnumServices->Next( WBEM_INFINITE, MAX_ENUM_MODULES, pObjects, &ulReturned );
if ( (HRESULT) WBEM_S_FALSE == hr )
{
// we've reached the end of enumeration .. set the flag
bCanExit = TRUE;
}
else
{
if ( ( (HRESULT) WBEM_S_TIMEDOUT == hr ) || FAILED( hr ))
{
// some error has occured ... oooppps
WMISaveError( hr );
SetLastError( ( DWORD )STG_E_UNKNOWN );
break;
}
}
// loop thru the objects and save the info
for( ULONG ul = 0; ul < ulReturned; ul++ )
{
// get the file name
bResult = PropertyGet( pObjects[ ul ], CIM_DATAFILE_PROPERTY_FILENAME, strFileName );
if ( FALSE == bResult )
{
continue;
}
// get the extension
bResult = PropertyGet( pObjects[ ul ], CIM_DATAFILE_PROPERTY_EXTENSION, strExtension );
if ( FALSE == bResult )
{
continue;
}
// format the module name
strModule.Format( L"%s.%s", strFileName, strExtension );
// check whether this module needs to be added to the list
if ( ( 0 == m_strModules.GetLength() ) || ( 0 == StringCompare( strModule, m_strModules, TRUE, dwLength ) ) )
{
// add the info the userdata ( for us we will get that in the form of an array
lIndex = DynArrayAppendString( arrModules, strModule, 0 );
if ( -1 == lIndex )
{
for( ULONG ulIndex = ul; ulIndex < ulReturned; ulIndex++ )
{
SAFE_RELEASE( pObjects[ ulIndex ] );
}
SAFE_RELEASE( pEnumServices );
// append is failed .. this could be because of lack of memory .. stop the enumeration
return FALSE;
}
}
// release the interface
SAFE_RELEASE( pObjects[ ul ] );
}
} while ( FALSE == bCanExit );
}
catch( _com_error& e )
{
SAFE_RELEASE( pEnumServices );
// save the error
WMISaveError( e );
return FALSE;
}
catch( CHeap_Exception )
{
SAFE_RELEASE( pEnumServices );
// out of memory
WMISaveError( E_OUTOFMEMORY );
return FALSE;
}
// release the objects to NULL's
for( DWORD dw = 0; dw < MAX_ENUM_MODULES; dw++ )
{
// release all the objects
SAFE_RELEASE( pObjects[ dw ] );
}
// now release the enumeration object
SAFE_RELEASE( pEnumServices );
// return
return TRUE;
}
#ifndef _WIN64
BOOL EnumLoadedModulesProc( LPSTR lpszModuleName, ULONG ulModuleBase, ULONG ulModuleSize, PVOID pUserData )
#else
BOOL EnumLoadedModulesProc64( LPSTR lpszModuleName, DWORD64 ulModuleBase, ULONG ulModuleSize, PVOID pUserData )
#endif
/*++
Routine Description:
Arguments:
[ in ] lpszModuleName : Contains module name.
[ in out ] ulModuleBase :
[ in ] ulModuleSize :
[ in ] pUserData : Username information.
Return Value:
TRUE if successful else FALSE.
--*/
{
// local variables
CHString str;
LONG lIndex = 0;
TARRAY arrModules = NULL;
PTMODULESINFO pModulesInfo = NULL;
// check the input values
if ( ( NULL == lpszModuleName ) || ( NULL == pUserData ) )
{
return FALSE;
}
// check the internal array info
pModulesInfo = (PTMODULESINFO) pUserData;
if ( ( SIGNATURE_MODULES != pModulesInfo->dwSignature ) || ( NULL == pModulesInfo->arrModules ) )
{
return FALSE;
}
// get the array pointer into the local variable
arrModules = (TARRAY) pModulesInfo->arrModules;
try
{
// copy the module name into the local string variable
// ( conversion from multibyte to unicode will automatically take place )
str = lpszModuleName;
// check whether this module needs to be added to the list
if ( ( NULL == pModulesInfo->pwszModule ) ||
( 0 == StringCompare( str, pModulesInfo->pwszModule, TRUE, pModulesInfo->dwLength ) ) )
{
// add the info the userdata ( for us we will get that in the form of an array
lIndex = DynArrayAppendString( arrModules, str, 0 );
if ( -1 == lIndex )
{
// append is failed .. this could be because of lack of memory .. stop the enumeration
return FALSE;
}
}
}
catch( CHeap_Exception )
{
// out of memory stop the enumeration
return FALSE;
}
// success .. continue the enumeration
return TRUE;
}
VOID
CTaskList::PrepareColumns(
void
)
/*++
Routine Description:
Prepares the columns information.
Arguments:
NONE
Return Value:
NONE
--*/
{
// local variables
PTCOLUMNS pCurrentColumn = NULL;
// host name
pCurrentColumn = m_pColumns + CI_HOSTNAME;
pCurrentColumn->dwWidth = COLWIDTH_HOSTNAME;
pCurrentColumn->dwFlags = SR_TYPE_STRING | SR_HIDECOLUMN;
pCurrentColumn->pFunction = NULL;
pCurrentColumn->pFunctionData = NULL;
StringCopy( pCurrentColumn->szFormat, NULL_STRING, MAX_COL_FORMAT );
StringCopy( pCurrentColumn->szColumn, COLHEAD_HOSTNAME, MAX_COL_HEADER );
// status
pCurrentColumn = m_pColumns + CI_STATUS;
pCurrentColumn->dwWidth = COLWIDTH_STATUS;
pCurrentColumn->dwFlags = SR_TYPE_STRING | SR_HIDECOLUMN | SR_SHOW_NA_WHEN_BLANK;
pCurrentColumn->pFunction = NULL;
pCurrentColumn->pFunctionData = NULL;
StringCopy( pCurrentColumn->szFormat, NULL_STRING, MAX_COL_FORMAT );
StringCopy( pCurrentColumn->szColumn, COLHEAD_STATUS, MAX_COL_HEADER );
// image name
pCurrentColumn = m_pColumns + CI_IMAGENAME;
pCurrentColumn->dwWidth = COLWIDTH_IMAGENAME;
pCurrentColumn->dwFlags = SR_TYPE_STRING | SR_HIDECOLUMN;
pCurrentColumn->pFunction = NULL;
pCurrentColumn->pFunctionData = NULL;
StringCopy( pCurrentColumn->szFormat, NULL_STRING, MAX_COL_FORMAT );
StringCopy( pCurrentColumn->szColumn, COLHEAD_IMAGENAME, MAX_COL_HEADER );
// pid
pCurrentColumn = m_pColumns + CI_PID;
pCurrentColumn->dwWidth = COLWIDTH_PID;
pCurrentColumn->dwFlags = SR_TYPE_NUMERIC | SR_HIDECOLUMN;
pCurrentColumn->pFunction = NULL;
pCurrentColumn->pFunctionData = NULL;
StringCopy( pCurrentColumn->szFormat, NULL_STRING, MAX_COL_FORMAT );
StringCopy( pCurrentColumn->szColumn, COLHEAD_PID, MAX_COL_HEADER );
// session name
pCurrentColumn = m_pColumns + CI_SESSIONNAME;
pCurrentColumn->dwWidth = COLWIDTH_SESSIONNAME;
pCurrentColumn->dwFlags = SR_TYPE_STRING | SR_HIDECOLUMN;
pCurrentColumn->pFunction = NULL;
pCurrentColumn->pFunctionData = NULL;
StringCopy( pCurrentColumn->szFormat, NULL_STRING, MAX_COL_FORMAT );
StringCopy( pCurrentColumn->szColumn, COLHEAD_SESSIONNAME, MAX_COL_HEADER );
// session#
pCurrentColumn = m_pColumns + CI_SESSION;
pCurrentColumn->dwWidth = COLWIDTH_SESSION;
pCurrentColumn->dwFlags = SR_TYPE_STRING | SR_ALIGN_LEFT | SR_HIDECOLUMN;
pCurrentColumn->pFunction = NULL;
pCurrentColumn->pFunctionData = NULL;
StringCopy( pCurrentColumn->szFormat, NULL_STRING, MAX_COL_FORMAT );
StringCopy( pCurrentColumn->szColumn, COLHEAD_SESSION, MAX_COL_HEADER );
// window name
pCurrentColumn = m_pColumns + CI_WINDOWTITLE;
pCurrentColumn->dwWidth = COLWIDTH_WINDOWTITLE;
pCurrentColumn->dwFlags = SR_TYPE_STRING | SR_HIDECOLUMN | SR_SHOW_NA_WHEN_BLANK;
pCurrentColumn->pFunction = NULL;
pCurrentColumn->pFunctionData = NULL;
StringCopy( pCurrentColumn->szFormat, NULL_STRING, MAX_COL_FORMAT );
StringCopy( pCurrentColumn->szColumn, COLHEAD_WINDOWTITLE, MAX_COL_HEADER );
// user name
pCurrentColumn = m_pColumns + CI_USERNAME;
pCurrentColumn->dwWidth = COLWIDTH_USERNAME;
pCurrentColumn->dwFlags = SR_TYPE_STRING | SR_HIDECOLUMN;
pCurrentColumn->pFunction = NULL;
pCurrentColumn->pFunctionData = NULL;
StringCopy( pCurrentColumn->szFormat, NULL_STRING, MAX_COL_FORMAT );
StringCopy( pCurrentColumn->szColumn, COLHEAD_USERNAME, MAX_COL_HEADER );
// cpu time
pCurrentColumn = m_pColumns + CI_CPUTIME;
pCurrentColumn->dwWidth = COLWIDTH_CPUTIME;
pCurrentColumn->dwFlags = SR_TYPE_STRING | SR_ALIGN_LEFT | SR_HIDECOLUMN;
pCurrentColumn->pFunction = NULL;
pCurrentColumn->pFunctionData = NULL;
StringCopy( pCurrentColumn->szFormat, NULL_STRING, MAX_COL_FORMAT );
StringCopy( pCurrentColumn->szColumn, COLHEAD_CPUTIME, MAX_COL_HEADER );
// mem usage
pCurrentColumn = m_pColumns + CI_MEMUSAGE;
pCurrentColumn->dwWidth = COLWIDTH_MEMUSAGE;
pCurrentColumn->dwFlags = SR_TYPE_STRING | SR_ALIGN_LEFT | SR_HIDECOLUMN;
pCurrentColumn->pFunction = NULL;
pCurrentColumn->pFunctionData = NULL;
StringCopy( pCurrentColumn->szFormat, NULL_STRING, MAX_COL_FORMAT );
StringCopy( pCurrentColumn->szColumn, COLHEAD_MEMUSAGE, MAX_COL_HEADER );
// services
pCurrentColumn = m_pColumns + CI_SERVICES;
pCurrentColumn->dwWidth = COLWIDTH_MODULES_WRAP;
pCurrentColumn->dwFlags = SR_ARRAY | SR_TYPE_STRING | SR_NO_TRUNCATION | SR_HIDECOLUMN | SR_SHOW_NA_WHEN_BLANK;
pCurrentColumn->pFunction = NULL;
pCurrentColumn->pFunctionData = NULL;
StringCopy( pCurrentColumn->szFormat, NULL_STRING, MAX_COL_FORMAT );
StringCopy( pCurrentColumn->szColumn, COLHEAD_SERVICES, MAX_COL_HEADER );
// modules
pCurrentColumn = m_pColumns + CI_MODULES;
pCurrentColumn->dwWidth = COLWIDTH_MODULES_WRAP;
pCurrentColumn->dwFlags = SR_ARRAY | SR_TYPE_STRING | SR_NO_TRUNCATION | SR_HIDECOLUMN | SR_SHOW_NA_WHEN_BLANK;
pCurrentColumn->pFunction = NULL;
pCurrentColumn->pFunctionData = NULL;
StringCopy( pCurrentColumn->szFormat, NULL_STRING, MAX_COL_FORMAT );
StringCopy( pCurrentColumn->szColumn, COLHEAD_MODULES, MAX_COL_HEADER );
//
// based on the option selected by the user .. show only needed columns
if ( TRUE == m_bAllServices )
{
( m_pColumns + CI_IMAGENAME )->dwFlags &= ~( SR_HIDECOLUMN );
( m_pColumns + CI_PID )->dwFlags &= ~( SR_HIDECOLUMN );
( m_pColumns + CI_SERVICES )->dwFlags &= ~( SR_HIDECOLUMN );
}
else if ( TRUE == m_bAllModules )
{
( m_pColumns + CI_IMAGENAME )->dwFlags &= ~( SR_HIDECOLUMN );
( m_pColumns + CI_PID )->dwFlags &= ~( SR_HIDECOLUMN );
( m_pColumns + CI_MODULES )->dwFlags &= ~( SR_HIDECOLUMN );
}
else
{
// default ... enable min. columns
( m_pColumns + CI_IMAGENAME )->dwFlags &= ~( SR_HIDECOLUMN );
( m_pColumns + CI_PID )->dwFlags &= ~( SR_HIDECOLUMN );
( m_pColumns + CI_SESSIONNAME )->dwFlags &= ~( SR_HIDECOLUMN );
( m_pColumns + CI_SESSION )->dwFlags &= ~( SR_HIDECOLUMN );
( m_pColumns + CI_MEMUSAGE )->dwFlags &= ~( SR_HIDECOLUMN );
// check if verbose option is specified .. show other columns
if ( TRUE == m_bVerbose )
{
( m_pColumns + CI_STATUS )->dwFlags &= ~( SR_HIDECOLUMN );
( m_pColumns + CI_USERNAME )->dwFlags &= ~( SR_HIDECOLUMN );
( m_pColumns + CI_CPUTIME )->dwFlags &= ~( SR_HIDECOLUMN );
( m_pColumns + CI_WINDOWTITLE )->dwFlags &= ~( SR_HIDECOLUMN );
}
}
}