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.
 
 
 
 
 
 

1500 lines
45 KiB

// *********************************************************************************
//
// Copyright (c) Microsoft Corporation
//
// Module Name:
//
// TaskKill.cpp
//
// Abstract:
//
// This module implements the termination of processes runnging on either local
// or remote system
//
// Syntax:
// ------
// TaskKill.exe [ -s server [ -u username [ -p password ] ] ] [ -f ] [ -t ]
// [ -fi filter ] [ -im imagename | -pid pid ]
//
// Author:
//
// Sunil G.V.N. Murali ([email protected]) 26-Nov-2000
//
// Revision History:
//
// Sunil G.V.N. Murali ([email protected]) 26-Nov-2000 : Created It.
//
// *********************************************************************************
#include "pch.h"
#include "wmi.h"
#include "TaskKill.h"
//
// local structures
//
typedef struct __tagWindowTitles
{
LPWSTR pwszDesk;
LPWSTR pwszWinsta;
BOOL bFirstLoop;
TARRAY arrWindows;
} TWINDOWTITLES, *PTWINDOWTITLES;
//
// private functions ... prototypes
//
BOOL CALLBACK EnumWindowsProc( HWND hWnd, LPARAM lParam );
BOOL CALLBACK EnumDesktopsFunc( LPWSTR pwsz, LPARAM lParam );
BOOL CALLBACK EnumWindowStationsFunc( LPWSTR pwsz, LPARAM lParam );
BOOL CALLBACK EnumMessageWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam );
BOOL GetPerfDataBlock( HKEY hKey, LPWSTR szObjectIndex, PPERF_DATA_BLOCK* ppdb );
DWORD
__cdecl wmain(
IN DWORD argc,
IN LPCTSTR argv[]
)
/*++
Routine Description:
This the entry point to this utility.
Arguments:
[ in ] argc : argument(s) count specified at the command prompt
[ in ] argv : argument(s) specified at the command prompt
Return Value:
The below are actually not return values but are the exit values
returned to the OS by this application
0 : utility is successfull
1 : utility failed
--*/
{
// local variables
CTaskKill taskkill;
BOOL bResult = FALSE;
DWORD dwExitCode = 0;
// initialize the taskkill utility
if ( taskkill.Initialize() == FALSE )
{
DISPLAY_GET_REASON();
EXIT_PROCESS( 1 );
}
// now do parse the command line options
if ( taskkill.ProcessOptions( argc, argv ) == FALSE )
{
DISPLAY_GET_REASON();
EXIT_PROCESS( 1 );
}
// check whether usage has to be displayed or not
if ( taskkill.m_bUsage == TRUE )
{
// show the usage of the utility
taskkill.Usage();
// quit from the utility
EXIT_PROCESS( 0 );
}
// now validate the filters and check the result of the filter validation
if ( taskkill.ValidateFilters() == FALSE )
{
// invalid filter
// SPECIAL:
// -------
// for the custom filter "pid" we are setting the tag "INFO:" before
// the message in the filter validation part itself
// so, check and display
// display the message
DISPLAY_GET_REASON();
EXIT_PROCESS( 1 );
}
// enable the kill privileges
if ( taskkill.EnableDebugPriv() == FALSE )
{
// show the error message and exit
SaveLastError();
DISPLAY_GET_REASON();
EXIT_PROCESS( 1 );
}
// connect to the server
bResult = taskkill.Connect();
if ( FALSE == bResult )
{
// show the error message
DISPLAY_GET_REASON();
EXIT_PROCESS( 1 );
}
// load the data and check
bResult = taskkill.LoadTasks();
if ( FALSE == bResult )
{
// show the error message
DISPLAY_GET_REASON();
EXIT_PROCESS( 1 );
}
// invoke the actual termination and get the exit code
bResult = taskkill.DoTerminate( dwExitCode );
if ( FALSE == bResult )
{
// NOTE: the 'FALSE' return value indicates that some major problem has occured
// while trying to terminate the process. Still the exit code will be determined by
// the function only. Do not change/set the exit code value
DISPLAY_GET_REASON();
}
// exit from the utility
EXIT_PROCESS( dwExitCode );
}
BOOL
CTaskKill::Connect(
void
)
/*++
Routine Description:
connects to the remote as well as remote system's WMI
Arguments:
NONE
Return Value:
TRUE : if connection is successful
FALSE : if connection is unsuccessful
--*/
{
// local variables
BOOL bResult = FALSE;
HRESULT hr = S_OK;
// release the existing auth identity structure
WbemFreeAuthIdentity( &m_pAuthIdentity );
// connect to WMI
bResult = ConnectWmiEx( m_pWbemLocator,
&m_pWbemServices, m_strServer, m_strUserName, m_strPassword,
&m_pAuthIdentity, m_bNeedPassword, WMI_NAMESPACE_CIMV2, &m_bLocalSystem );
hr = GetLastError();
// check the result of connection
if ( FALSE == bResult )
{
return FALSE;
}
#ifndef _WIN64
// determine the type of the platform if modules info is required
if ( ( TRUE == m_bLocalSystem ) && ( TRUE == m_bNeedModulesInfo ) )
{
// sub-local variables
DWORD dwPlatform = 0;
// get the platform type
dwPlatform = GetTargetPlatformEx( m_pWbemServices, m_pAuthIdentity );
// if the platform is not 32-bit, error
if ( dwPlatform != PLATFORM_X86 )
{
// let the tool use WMI calls instead of Win32 API
m_bUseRemote = TRUE;
}
}
#endif
try
{
// check the local credentials and if need display warning
if ( WBEM_E_LOCAL_CREDENTIALS == hr )
{
WMISaveError( WBEM_E_LOCAL_CREDENTIALS );
ShowMessageEx( stderr, 2, FALSE, L"%1 %2",
TAG_WARNING, GetReason() );
}
// check the remote system version and its compatiblity
if ( FALSE == m_bLocalSystem )
{
// check the version compatibility
DWORD dwVersion = 0;
dwVersion = GetTargetVersionEx( m_pWbemServices, m_pAuthIdentity );
if ( IsCompatibleOperatingSystem( dwVersion ) == FALSE )
{
SetReason( ERROR_REMOTE_INCOMPATIBLE );
return FALSE;
}
}
// save the server name
m_strUNCServer = L"";
if ( m_strServer.GetLength() != 0 )
{
// check whether the server name is in UNC format or not .. if not prepare it
m_strUNCServer = m_strServer;
if ( IsUNCFormat( m_strServer ) == FALSE )
{
m_strUNCServer.Format( L"\\\\%s", m_strServer );
}
}
}
catch( _com_error& e )
{
WMISaveError( e );
return FALSE;
}
// return the result
return TRUE;
}
BOOL
CTaskKill::LoadTasks(
void
)
/*++
Routine Description:
initiate the enumeration
Arguments:
NONE
Return Value:
TRUE : if successful
FALSE : if unsuccessful
--*/
{
// local variables
HRESULT hr = S_OK;
IWbemClassObject* pObject = NULL;
// check the services object
if ( ( NULL == m_pWbemServices ) ||
( NULL != m_pWbemEnumObjects ) )
{
SetLastError( ( DWORD )STG_E_UNKNOWN );
SaveLastError();
return FALSE;
}
try
{
// do the optimization
DoOptimization();
// load the tasks from WMI based on generated query
hr = m_pWbemServices->ExecQuery( _bstr_t( WMI_QUERY_TYPE ), _bstr_t( m_strQuery ),
WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, &m_pWbemEnumObjects );
// check the result of the ExecQuery
if ( FAILED( hr ) )
{
WMISaveError( hr );
return FALSE;
}
// set the interface security and check the result
hr = SetInterfaceSecurity( m_pWbemEnumObjects, m_pAuthIdentity );
if ( FAILED( hr ) )
{
WMISaveError( hr );
return FALSE;
}
//
// get the reference to the Win32_Process class object
// and then reference to the input parameters of the "Terminate" method
SAFE_EXECUTE( m_pWbemServices->GetObject(
_bstr_t( CLASS_PROCESS ), 0, NULL, &pObject, NULL ) );
SAFE_EXECUTE( pObject->GetMethod(
_bstr_t( WIN32_PROCESS_METHOD_TERMINATE ), 0, &m_pWbemTerminateInParams, NULL ) );
// release the WMI object
SAFE_RELEASE( pObject );
//
// retrieve the window title information if needed
// remove the current window titles information
DynArrayRemoveAll( m_arrWindowTitles );
// for the local system, enumerate the window titles of the processes
// there is no provision for collecting the window titles of remote processes
if ( TRUE == m_bLocalSystem )
{
// prepare the tasks list info
TWINDOWTITLES windowtitles;
windowtitles.pwszDesk = NULL;
windowtitles.pwszWinsta = NULL;
windowtitles.bFirstLoop = FALSE;
windowtitles.arrWindows = m_arrWindowTitles;
EnumWindowStations( EnumWindowStationsFunc, ( LPARAM ) &windowtitles );
// free the memory allocated with _tcsdup string function
if ( NULL != windowtitles.pwszDesk )
{
free( windowtitles.pwszDesk );
}
if ( NULL != windowtitles.pwszWinsta )
{
free( windowtitles.pwszWinsta );
}
}
// load the extended tasks information
LoadTasksEx(); // NOTE: here we are not much bothered abt the return value
}
catch( _com_error& e )
{
// save the error
SAFE_RELEASE( pObject );
WMISaveError( e.Error() );
return FALSE;
}
catch( CHeap_Exception )
{
// save the error
SAFE_RELEASE( pObject );
WMISaveError( E_OUTOFMEMORY );
return FALSE;
}
// return success
return TRUE;
}
BOOL
CTaskKill::LoadTasksEx(
void
)
/*++
Routine Description:
Store other information such as module, service etc. of a process
running on a system.
Arguments:
NONE
Return Value:
TRUE if success else FALSE is returned.
--*/
{
// local variables
BOOL bResult = FALSE;
//
// NOTE: we are relying on NET API for getting the user context / services info
// so if any one of them is needed, establish connection to the remote system using NET API
if ( ( FALSE == m_bNeedModulesInfo ) &&
( FALSE == m_bNeedUserContextInfo ) &&
( FALSE == m_bNeedServicesInfo )
)
{
return TRUE;
}
// init
m_bCloseConnection = FALSE;
try
{
// we need to use NET API only in case connecting to the remote system
// with credentials information i.e; m_pAuthIdentity is not NULL
if ( ( FALSE == m_bLocalSystem ) && ( NULL != m_pAuthIdentity ) )
{
// sub-local variables
DWORD dwConnect = 0;
LPCWSTR pwszUser = NULL;
LPCWSTR pwszPassword = NULL;
// identify the password to connect to the remote system
pwszPassword = m_pAuthIdentity->Password;
if ( 0 != m_strUserName.GetLength() )
{
pwszUser = m_strUserName;
}
// establish connection to the remote system using NET API
// this we need to do only for remote system
dwConnect = NO_ERROR;
m_bCloseConnection = TRUE;
dwConnect = ConnectServer( m_strUNCServer, pwszUser, pwszPassword );
if ( NO_ERROR != dwConnect )
{
// connection should not be closed .. this is because we didn't establish the connection
m_bCloseConnection = FALSE;
// this might be 'coz of the conflict in the credentials ... check that
if ( ERROR_SESSION_CREDENTIAL_CONFLICT != dwConnect )
{
// return failure
return FALSE;
}
}
// check the whether we need to close the connection or not
// if user name is NULL (or) password is NULL then don't close the connection
if ( ( NULL == pwszUser ) || ( NULL == pwszPassword ) )
{
m_bCloseConnection = FALSE;
}
}
// connect to the remote system's winstation
// sub-local variables
HANDLE hServer = NULL;
bResult = TRUE;
hServer = SERVERNAME_CURRENT;
if ( FALSE == m_bLocalSystem )
{
// sub-local variables
LPWSTR pwsz = NULL;
// connect to the winsta and check the result
pwsz = m_strUNCServer.GetBuffer( m_strUNCServer.GetLength() );
hServer = WinStationOpenServerW( pwsz );
// proceed furthur only if winstation of the remote system is successfully opened
if ( NULL == hServer )
{
bResult = FALSE;
}
}
// prepare to get the user context info .. if needed
if ( ( TRUE == m_bNeedUserContextInfo ) && ( TRUE == bResult ) )
{
// get all the process details
m_bIsHydra = FALSE;
bResult = WinStationGetAllProcesses( hServer,
GAP_LEVEL_BASIC, &m_ulNumberOfProcesses, (PVOID*) &m_pProcessInfo );
// check the result
if ( FALSE == bResult )
{
// Maybe a Hydra 4 server ?
// Check the return code indicating that the interface is not available.
if ( RPC_S_PROCNUM_OUT_OF_RANGE == GetLastError() )
{
// The new interface is not known
// It must be a Hydra 4 server
// try with the old interface
bResult = WinStationEnumerateProcesses( hServer, (PVOID*) &m_pProcessInfo );
// check the result of enumeration
if ( TRUE == bResult )
{
m_bIsHydra = TRUE;
}
}
else
{
// unknown error
// ????????????????????????????????????????????????????????????????
// dont know whatz happening to the memory allocated here
// we are getting AV when trying to free the memory allocated
// in the call to WinStationGetAllProcesses
// ????????????????????????????????????????????????????????????????
m_pProcessInfo = NULL;
}
}
}
// close the connection to the winsta
if ( NULL != hServer )
{
WinStationCloseServer( hServer );
}
}
catch( CHeap_Exception )
{
SetLastError( ( DWORD )E_OUTOFMEMORY );
SaveLastError();
return FALSE;
}
// check whether we need services info or not
if ( TRUE == m_bNeedServicesInfo )
{
// load the services
bResult = LoadServicesInfo();
// check the result
if ( FALSE == bResult )
{
return FALSE;
}
}
// check whether we need modules info or not
if ( TRUE == m_bNeedModulesInfo )
{
// load the modules information
bResult = LoadModulesInfo();
// check the result
if ( FALSE == bResult )
{
return FALSE;
}
}
// NETWORK OPTIMIZATION -
// while progressing furthur in display of the data, we don't need the connection
// to the remote system with NET API ... but the connection should be live
// if user name has to be retrieved .. so check if user name info is needed or not
// if not, close the connection
if ( ( FALSE == m_bNeedUserContextInfo ) && ( TRUE == m_bCloseConnection ) )
{
m_bCloseConnection = FALSE; // reset the flag
CloseConnection( m_strUNCServer ); // close connection
}
// return
return TRUE;
}
BOOL
CTaskKill::LoadModulesInfo(
void
)
/*++
Routine Description:
Store module information of a process.
Arguments:
NONE
Return Value:
TRUE if success else FALSE is returned.
--*/
{
// local variables
HKEY hKey = NULL;
LONG lReturn = 0;
BOOL bResult = FALSE;
BOOL bImagesObject = FALSE;
BOOL bAddressSpaceObject = FALSE;
PPERF_OBJECT_TYPE pot = NULL;
// check whether we need the modules infor or not
// NOTE: we need to load the performance data only in case if user is querying for remote system only
if ( ( FALSE == m_bNeedModulesInfo ) || ( TRUE == m_bLocalSystem ) )
{
return TRUE;
}
try
{
// open the remote system performance data key
lReturn = RegConnectRegistry( m_strUNCServer, HKEY_PERFORMANCE_DATA, &hKey );
if ( ERROR_SUCCESS != lReturn )
{
SetLastError( ( DWORD )lReturn );
SaveLastError();
return FALSE;
}
// get the performance object ( images )
bResult = GetPerfDataBlock( hKey, L"740", &m_pdb );
if ( FALSE == bResult )
{
// close the registry key and return
RegCloseKey( hKey );
return FALSE;
}
// check the validity of the perf block
if ( 0 != StringCompare( m_pdb->Signature, L"PERF", FALSE, 4 ) )
{
// close the registry key and return
RegCloseKey( hKey );
// set the error message
SetLastError( ( DWORD )ERROR_ACCESS_DENIED );
SaveLastError();
return FALSE;
}
// close the registry key and return
RegCloseKey( hKey );
//
// check whether we got both 740 and 786 blocks or not
//
bImagesObject = FALSE;
bAddressSpaceObject = FALSE;
pot = (PPERF_OBJECT_TYPE) ( (LPBYTE) m_pdb + m_pdb->HeaderLength );
for( DWORD dw = 0; dw < m_pdb->NumObjectTypes; dw++ )
{
if ( 740 == pot->ObjectNameTitleIndex )
{
bImagesObject = TRUE;
}
else
{
if ( 786 == pot->ObjectNameTitleIndex )
{
bAddressSpaceObject = TRUE;
}
}
// move to the next object
if( 0 != pot->TotalByteLength )
{
pot = ( (PPERF_OBJECT_TYPE) ((PBYTE) pot + pot->TotalByteLength));
}
}
}
catch( CHeap_Exception )
{
WMISaveError( E_OUTOFMEMORY );
if( NULL != hKey )
{
RegCloseKey( hKey );
}
return FALSE;
}
// release the resource
if ( NULL != hKey )
{
RegCloseKey( hKey );
hKey = NULL;
}
// check whether we got the needed objects or not
if ( ( FALSE == bImagesObject ) || ( FALSE == bAddressSpaceObject ) )
{
SetLastError( ( DWORD )ERROR_ACCESS_DENIED );
SaveLastError();
return FALSE;
}
// return
return TRUE;
}
BOOL
CTaskKill::LoadUserNameFromWinsta(
OUT CHString& strDomain,
OUT CHString& strUserName
)
/*++
Routine Description:
Store username of a process obtained from window station.
Arguments:
OUT strDomain : Contains domain name string.
OUT strUserName : Contains username string.
Return Value:
TRUE if success else FALSE is returned.
--*/
{
// local variables
PSID pSid = NULL;
BOOL bResult = FALSE;
LPWSTR pwszUser = NULL;
LPWSTR pwszDomain = NULL;
LPCWSTR pwszServer = NULL;
DWORD dwUserLength = 0;
DWORD dwDomainLength = 0;
SID_NAME_USE siduse;
// check whether winsta data exists or not
if ( NULL == m_pProcessInfo )
{
return FALSE;
}
try
{
// allocate buffers
dwUserLength = 128;
dwDomainLength = 128;
pwszUser = strUserName.GetBufferSetLength( dwUserLength );
pwszDomain = strDomain.GetBufferSetLength( dwDomainLength );
//
// find for the appropriate the process
pSid = NULL;
if ( FALSE == m_bIsHydra )
{
// sub-local variables
PTS_ALL_PROCESSES_INFO ptsallpi = NULL;
PTS_SYSTEM_PROCESS_INFORMATION pspi = NULL;
// loop ...
ptsallpi = (PTS_ALL_PROCESSES_INFO) m_pProcessInfo;
for( ULONG ul = 0; ul < m_ulNumberOfProcesses; ul++ )
{
pspi = ( PTS_SYSTEM_PROCESS_INFORMATION )( ptsallpi[ ul ].pspiProcessInfo );
if ( pspi->UniqueProcessId == m_dwProcessId )
{
// get the SID and convert it into
pSid = ptsallpi[ ul ].pSid;
break; // break from the loop
}
}
}
else
{
//
// HYDRA ...
//
DWORD dwTotalOffset = 0;
PTS_SYSTEM_PROCESS_INFORMATION pspi = NULL;
PCITRIX_PROCESS_INFORMATION pcpi = NULL;
// traverse thru the process info and find the process id
dwTotalOffset = 0;
pspi = ( PTS_SYSTEM_PROCESS_INFORMATION ) m_pProcessInfo;
for( ;; )
{
// check the processid
if ( pspi->UniqueProcessId == m_dwProcessId )
{
break;
}
// check whether any more processes exist or not
if( 0 == pspi->NextEntryOffset )
{
break;
}
// position to the next process info
dwTotalOffset += pspi->NextEntryOffset;
pspi = (PTS_SYSTEM_PROCESS_INFORMATION) &m_pProcessInfo[ dwTotalOffset ];
}
// get the citrix_information which follows the threads
pcpi = (PCITRIX_PROCESS_INFORMATION)
( ((PUCHAR) pspi) + sizeof( TS_SYSTEM_PROCESS_INFORMATION ) +
(sizeof( SYSTEM_THREAD_INFORMATION ) * pspi->NumberOfThreads) );
// check the magic number .. if it is not valid ... we haven't got SID
if( CITRIX_PROCESS_INFO_MAGIC == pcpi->MagicNumber )
{
pSid = pcpi->ProcessSid;
}
}
// check the sid value
if ( NULL == pSid )
{
// SPECIAL CASE:
// -------------
// PID -> 0 will have a special hard coded user name info
if ( 0 == m_dwProcessId )
{
bResult = TRUE;
StringCopyW( pwszUser, PID_0_USERNAME, dwUserLength );
StringCopyW( pwszDomain, PID_0_DOMAIN, dwDomainLength );
}
// release the buffer
strDomain.ReleaseBuffer();
strUserName.ReleaseBuffer();
return bResult;
}
// determine the server
pwszServer = NULL;
if ( FALSE == m_bLocalSystem )
{
pwszServer = m_strUNCServer;
}
// map the sid to the user name
bResult = LookupAccountSid( pwszServer, pSid,
pwszUser, &dwUserLength, pwszDomain, &dwDomainLength, &siduse );
// release the buffer
strDomain.ReleaseBuffer();
strUserName.ReleaseBuffer();
}
catch( CHeap_Exception )
{
WMISaveError( E_OUTOFMEMORY );
return FALSE;
}
// return the result
return bResult;
}
BOOL
CTaskKill::LoadServicesInfo(
void
)
/*++
Routine Description:
Store service infomration of a process.
Arguments:
NONE
Return Value:
TRUE if success else FALSE is returned.
--*/
{
// local variables
DWORD dw = 0; // looping variable
DWORD dwSize = 0; // used in memory allocation
DWORD dwResume = 0; // used in EnumServicesStatusEx
BOOL bResult = FALSE; // captures the result of EnumServicesStatusEx
SC_HANDLE hScm = NULL; // holds the handle to the service
DWORD dwExtraNeeded = 0; // used in EnumServicesStatusEx and memory allocation
LPCWSTR pwszServer = NULL;
LPENUM_SERVICE_STATUS_PROCESS pInfo = NULL; // holds the services info
// Initialize the output parameter(s).
m_dwServicesCount = 0;
m_pServicesInfo = NULL;
// check whether we need to load the services info or not
if ( FALSE == m_bNeedServicesInfo )
{
return TRUE;
}
// determine the server
pwszServer = NULL;
if ( FALSE == m_bLocalSystem )
{
pwszServer = m_strUNCServer;
}
try
{
// Connect to the service controller and check the result
hScm = OpenSCManager( pwszServer, NULL, SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE );
if ( NULL == hScm )
{
// set the reason for the failure and return from here itself
SaveLastError();
return FALSE;
}
// enumerate the names of the active win32 services
// for this, first pass through the loop and allocate memory from an initial guess. (4K)
// if that isn't sufficient, we make another pass and allocate
// what is actually needed.
// (we only go through the loop a maximum of two times)
dw = 0; // no. of loops
dwResume = 0; // reset / initialize variables
dwSize = 4 * 1024; // reset / initialize variables
while ( 2 >= ++dw )
{
// set the size
dwSize += dwExtraNeeded;
// allocate memory for storing services information
pInfo = ( LPENUM_SERVICE_STATUS_PROCESS ) AllocateMemory( dwSize );
if ( NULL == pInfo )
{
// failed in allocating needed memory ... error
SetLastError( ( DWORD )E_OUTOFMEMORY );
SaveLastError();
return FALSE;
}
// enumerate services, the process identifier and additional flags for the service
dwResume = 0; // lets get all the services again
bResult = EnumServicesStatusEx( hScm, SC_ENUM_PROCESS_INFO, SERVICE_WIN32,
SERVICE_ACTIVE, ( LPBYTE ) pInfo, dwSize, &dwExtraNeeded, &m_dwServicesCount, &dwResume, NULL );
// check the result of the enumeration
if ( TRUE == bResult )
{
// successfully enumerated all the services information
break; // jump out of the loop
}
// first free the allocated memory
FreeMemory( ( LPVOID * ) &pInfo );
// now lets look at what is the error
if ( ERROR_MORE_DATA == GetLastError() )
{
// some more services are not listed because of less memory
// allocate some more memory and enumerate the remaining services info
continue;
}
else
{
// some strange error occured ... inform the same to the caller
SaveLastError(); // set the reason for the failure
CloseServiceHandle( hScm ); // close the handle to the service
return FALSE; // inform failure
}
}
}
catch( CHeap_Exception )
{
if( NULL != hScm )
{
CloseServiceHandle( hScm ); // close the handle to the service
}
WMISaveError( E_OUTOFMEMORY );
return FALSE;
}
// check whether there any services or not ... if services count is zero, free the memory
if ( 0 == m_dwServicesCount )
{
// no services exists
FreeMemory( ( LPVOID * ) &pInfo );
}
else
{
// set the local pointer to the out parameter
m_pServicesInfo = pInfo;
}
// inform success
return TRUE;
}
BOOL
GetPerfDataBlock(
IN HKEY hKey,
IN LPWSTR pwszObjectIndex,
IN PPERF_DATA_BLOCK* ppdb
)
/*++
Routine Description:
Rertieve performance data block.
Arguments:
[in] hKey : Contains handle to registry key.
[in] pwszObjectIndex : Contains index value of an object.
[out] ppdb : Contains performance data.
Return Value:
TRUE if success else FALSE is returned.
--*/
{
// local variables
LONG lReturn = 0;
DWORD dwBytes = 0;
BOOL bResult = FALSE;
// check the input parameters
if ( ( NULL == pwszObjectIndex ) ||
( NULL != *ppdb ) ||
( NULL == ppdb ) )
{
return FALSE;
}
// allocate memory for PERF_DATA_BLOCK
dwBytes = 32 * 1024; // initially allocate for 32 K
*ppdb = (PPERF_DATA_BLOCK) AllocateMemory( dwBytes );
if( NULL == *ppdb )
{
SetLastError( ( DWORD )E_OUTOFMEMORY );
SaveLastError();
return FALSE;
}
// get performance data on passed Object
lReturn = RegQueryValueEx( hKey, pwszObjectIndex, NULL, NULL, (LPBYTE) *ppdb, &dwBytes );
while( ERROR_MORE_DATA == lReturn )
{
// increase memory by 8 K
dwBytes += 8192;
// since we are attempting to re-allocate the memory -- and in that process
// some uncertain memory manipulations might occur -- for that reason,
// instead of trying to re-allocate memory, release the current memory and
// try to allocate if fresh
FreeMemory( ( LPVOID * ) ppdb );
// now allocate some more memory
*ppdb = NULL;
*ppdb = (PPERF_DATA_BLOCK) AllocateMemory( dwBytes );
if( NULL == *ppdb )
{
SetLastError( ( DWORD )E_OUTOFMEMORY );
SaveLastError();
return FALSE;
}
// try to get the info again
lReturn = RegQueryValueEx( hKey, pwszObjectIndex, NULL, NULL, (LPBYTE) *ppdb, &dwBytes );
}
// check the reason for coming out of the loop
bResult = TRUE;
if ( ERROR_SUCCESS != lReturn )
{
if ( NULL != *ppdb)
{
FreeMemory( ( LPVOID * ) ppdb );
*ppdb = NULL;
}
// save the error info
bResult = FALSE;
SetLastError( ( DWORD )lReturn );
SaveLastError();
}
// return the result
return bResult;
}
VOID
CTaskKill::DoOptimization(
void
)
/*++
Routine Description:
Enumerates the desktops available on a particular window station
This is a CALLBACK function ... called by EnumWindowStations API function
Arguments:
NONE
Return Value:
VOID
--*/
{
// local variables
DWORD dwCount = 0;
CHString strCondition;
BOOL bOptimized = FALSE;
LPCWSTR pwsz = NULL;
LPCWSTR pwszTask = NULL;
LPCWSTR pwszClause = NULL;
CHString strInternalQuery;
// do not the optimization if user requested the tree termination
if ( TRUE == m_bTree )
{
return;
}
try
{
// traverse thru list of specified tasks to kill and prepare the query
pwszClause = NULL_STRING;
dwCount = DynArrayGetCount( m_arrTasksToKill );
for( DWORD dw = 0; dw < dwCount; dw++ )
{
// get the task
pwszTask = DynArrayItemAsString( m_arrTasksToKill, dw );
if ( NULL == pwszTask )
{
continue;
}
// check the for the special input '*' which cannot be optimized
if ( 0 == StringCompare( pwszTask, L"*", TRUE, 0 ) )
{
return; // query should not be optimized ... return back
}
// now check whether wild-card is specified in the image name
if ( NULL != (pwsz = FindChar( pwszTask, L'*', 0 )) )
{
// the image name contains wild card in it - this cannot be included in query
if ( StringLength( pwsz, 0 ) == 1 )
{
continue;
}
}
// prepare the query based on the type of input
// NOTE: in case of numeric it might be a process id (or) image name
// we are not sure abt what it can be. So prepare query for both
if ( IsNumeric( pwszTask, 10, FALSE ) == TRUE )
{
// prepare condition
strCondition.Format( L" %s %s = %s", pwszClause,
WIN32_PROCESS_PROPERTY_PROCESSID, pwszTask );
}
else
{
// prepare the condition
strCondition.Format( L" %s %s = \"%s\"",
pwszClause, WIN32_PROCESS_PROPERTY_IMAGENAME, pwszTask );
}
// append to the final query
strInternalQuery += strCondition;
// from next time onwards query clause has to be added
bOptimized = TRUE;
pwszClause = WMI_CLAUSE_OR;
}
// do modifications to the query only if tasks were optimized
if ( TRUE == bOptimized )
{
// now this internal query has to be added to the main query
// before adding this check whether query optimization is done in filters or not
// if not, we have to add the where clause also
strCondition.Format( L"%s %s", m_strQuery,
(m_bFiltersOptimized == TRUE ? WMI_CLAUSE_AND : WMI_CLAUSE_WHERE) );
// now add the internal query to the final query
m_bTasksOptimized = TRUE;
m_strQuery.Format( L"%s (%s)", strCondition, strInternalQuery );
}
}
catch( CHeap_Exception )
{
// we can't anything here ... just return
SetLastError( ( DWORD )E_OUTOFMEMORY );
SaveLastError();
return;
}
}
BOOL
CALLBACK EnumWindowStationsFunc(
IN LPTSTR lpstr,
IN LPARAM lParam
)
/*++
Routine Description:
Enumerates the desktops available on a particular window station
This is a CALLBACK function ... called by EnumWindowStations API function
Arguments:
[ in ] lpstr : window station name
[ in ] lParam : user supplied parameter to this function
in this function, this points to TTASKSLIST structure variable
Return Value:
TRUE upon success and FALSE on failure
--*/
{
// local variables
HWINSTA hWinSta = NULL;
HWINSTA hwinstaSave = NULL;
PTWINDOWTITLES pWndTitles = ( PTWINDOWTITLES ) lParam;
// check the input arguments
if ( ( NULL == lpstr ) || ( NULL == lParam ) )
{
return FALSE;
}
// get and save the current window station
hwinstaSave = GetProcessWindowStation();
// open current tasks window station and change the context to the new workstation
hWinSta = OpenWindowStation( lpstr, FALSE, MAXIMUM_ALLOWED );
if ( NULL == hWinSta )
{
// failed in getting the process window station
SaveLastError();
return FALSE;
}
else
{
// change the context to the new workstation
if ( ( hWinSta != hwinstaSave ) && ( FALSE == SetProcessWindowStation( hWinSta ) ) )
{
// failed in changing the context
SaveLastError();
return FALSE;
}
// release the memory allocated for earlier window station
if ( NULL != pWndTitles->pwszWinsta )
{
free( pWndTitles->pwszWinsta );
pWndTitles->pwszWinsta = NULL;
}
// store the window station name
pWndTitles->pwszWinsta = _tcsdup( lpstr );
if ( NULL == pWndTitles->pwszWinsta )
{
SetLastError( ( DWORD )E_OUTOFMEMORY );
SaveLastError();
// restore the context to the previous windowstation
if (hWinSta != hwinstaSave)
{
SetProcessWindowStation( hwinstaSave );
CloseWindowStation( hWinSta );
}
return FALSE;
}
}
// enumerate all the desktops for this windowstation
EnumDesktops( hWinSta, EnumDesktopsFunc, lParam );
// restore the context to the previous windowstation
if (hWinSta != hwinstaSave)
{
SetProcessWindowStation( hwinstaSave );
CloseWindowStation( hWinSta );
}
// continue the enumeration
return TRUE;
}
BOOL
CALLBACK EnumDesktopsFunc(
IN LPTSTR lpstr,
IN LPARAM lParam
)
/*++
Routine Description:
Enumerates the windows on a particular desktop
This is a CALLBACK function ... called by EnumDesktops API function
Arguments:
[ in ] lpstr : desktop name
[ in ] lParam : user supplied parameter to this function
in this function, this points to TTASKSLIST structure variable
Return Value:
TRUE upon success and FALSE on failure
--*/
{
// local variables
HDESK hDesk = NULL;
HDESK hdeskSave = NULL;
PTWINDOWTITLES pWndTitles = ( PTWINDOWTITLES )lParam;
// check the input arguments
if ( ( NULL == lpstr ) || ( NULL == lParam ) )
{
return FALSE;
}
// get and save the current desktop
hdeskSave = GetThreadDesktop( GetCurrentThreadId() );
// open the tasks desktop and change the context to the new desktop
hDesk = OpenDesktop( lpstr, 0, FALSE, MAXIMUM_ALLOWED );
if ( NULL == hDesk )
{
// failed in getting the process desktop
SaveLastError();
return FALSE;
}
else
{
// change the context to the new desktop
if ( ( hDesk != hdeskSave ) && ( FALSE == SetThreadDesktop( hDesk ) ) )
{
// failed in changing the context
SaveLastError();
return FALSE;
}
// release the memory allocated for earlier window station
if ( NULL != pWndTitles->pwszDesk )
{
free( pWndTitles->pwszDesk );
pWndTitles->pwszDesk = NULL;
}
// store the desktop name
pWndTitles->pwszDesk = _tcsdup( lpstr );
if ( NULL == pWndTitles->pwszDesk )
{
SetLastError( ( DWORD )E_OUTOFMEMORY );
SaveLastError();
// restore the previous desktop
if (hDesk != hdeskSave)
{
SetThreadDesktop( hdeskSave );
CloseDesktop( hDesk );
}
return FALSE;
}
}
// enumerate all windows in the new desktop
// first try to get only the top level windows and visible windows only
( ( PTWINDOWTITLES ) lParam )->bFirstLoop = TRUE;
EnumWindows( ( WNDENUMPROC ) EnumWindowsProc, lParam );
EnumMessageWindows( ( WNDENUMPROC ) EnumWindowsProc, lParam );
// enumerate all windows in the new desktop
// now try to get window titles of all those processes whose we ignored earlier while
// looping first time
( ( PTWINDOWTITLES ) lParam )->bFirstLoop = FALSE;
EnumWindows( ( WNDENUMPROC ) EnumWindowsProc, lParam );
EnumMessageWindows( ( WNDENUMPROC ) EnumWindowsProc, lParam );
// restore the previous desktop
if (hDesk != hdeskSave)
{
SetThreadDesktop( hdeskSave );
CloseDesktop( hDesk );
}
// continue enumeration
return TRUE;
}
BOOL
CALLBACK EnumMessageWindows(
IN WNDENUMPROC lpEnumFunc,
IN LPARAM lParam
)
/*++
Routine Description:
Enumerates the message windows
Arguments:
[ in ] lpEnumFunc : address of call back function that has to be called for
each message window found
[ in ] lParam : user supplied parameter to this function
in this function, this points to TTASKSLIST structure variable
Return Value:
TRUE upon success and FALSE on failure
--*/
{
// local variables
HWND hWnd = NULL;
BOOL bResult = FALSE;
// check the input arguments
if ( ( NULL == lpEnumFunc ) || ( NULL == lParam ) )
{
return FALSE;
}
// enumerate all the message windows
do
{
// find the message window
hWnd = FindWindowEx( HWND_MESSAGE, hWnd, NULL, NULL );
// check whether we got the handle to the message window or not
if ( NULL != hWnd )
{
// explicitly call the windows enumerators call back function for this window
bResult = ( *lpEnumFunc )( hWnd, lParam );
// check the result of the enumeator call back function
if ( FALSE == bResult )
{
// terminate the enumeration
break;
}
}
} while ( NULL != hWnd );
// return the enumeration result
return bResult;
}
BOOL
CALLBACK EnumWindowsProc(
IN HWND hWnd,
IN LPARAM lParam
)
/*++
Routine Description:
call back called by the API for each window
retrives the window title and updates the accordingly
Arguments:
[ in ] hWnd : handle to the window
[ in ] lParam : user supplied parameter to this function
in this function, this points to TTASKSLIST structure variable
Return Value:
TRUE upon success and FALSE on failure
--*/
{
// local variables
LONG lIndex = 0;
DWORD dwPID = 0;
BOOL bVisible = FALSE;
BOOL bHung = FALSE;
TARRAY arrWindows = NULL;
PTWINDOWTITLES pWndTitles = NULL;
WCHAR szWindowTitle[ 256 ] = NULL_STRING;
// check the input arguments
if ( ( NULL == hWnd ) || ( NULL == lParam ) )
{
return FALSE;
}
// get the values from the lParam
pWndTitles = ( PTWINDOWTITLES ) lParam;
arrWindows = pWndTitles->arrWindows;
// get the processid for this window
if ( 0 == GetWindowThreadProcessId( hWnd, &dwPID ) )
{
// failed in getting the process id
return TRUE; // return but, proceed enumerating other window handle
}
// get the visibility state of the window
// if the window is not visible, and if this is the first we are enumerating the
// window titles, ignore this process
bVisible = GetWindowLong( hWnd, GWL_STYLE ) & WS_VISIBLE;
if ( ( FALSE == bVisible ) && ( TRUE == pWndTitles->bFirstLoop ) )
{
return TRUE; // return but, proceed enumerating other window handle
}
// check whether the current window ( for which we have the handle )
// is main window or not. we don't need child windows
if ( NULL != GetWindow(hWnd, GW_OWNER) )
{
// the current window handle is not for a top level window
return TRUE; // return but, proceed enumerating other window handle
}
// check if we are already got the window handle for the curren process or not
// save it only if we are not having it
lIndex = DynArrayFindDWORDEx( arrWindows, CTaskKill::twiProcessId, dwPID );
if ( -1 == lIndex )
{
// window for this process is not there ... save it
lIndex = DynArrayAppendRow( arrWindows, CTaskKill::twiCOUNT );
}
else
{
// check whether window details already exists or not
if ( NULL != DynArrayItemAsHandle2( arrWindows, lIndex, CTaskKill::twiHandle ) )
{
lIndex = -1; // window details already exists
}
}
// check if window details has to be saved or not ... if needed save them
if ( -1 != lIndex )
{
// check whether the application associated with this windows
// responding ( or ) not responding
bHung = IsHungAppWindow( hWnd );
// save the data
DynArraySetHandle2( arrWindows, lIndex, CTaskKill::twiHandle, hWnd );
DynArraySetBOOL2( arrWindows, lIndex, CTaskKill::twiHungInfo, bHung );
DynArraySetDWORD2( arrWindows, lIndex, CTaskKill::twiProcessId, dwPID );
DynArraySetString2( arrWindows, lIndex,
CTaskKill::twiWinSta, pWndTitles->pwszWinsta, 0 );
DynArraySetString2( arrWindows, lIndex,
CTaskKill::twiDesktop, pWndTitles->pwszDesk, 0 );
// get and save the window title
if ( 0 != GetWindowText( hWnd, szWindowTitle, SIZE_OF_ARRAY( szWindowTitle ) ) )
{
DynArraySetString2( arrWindows, lIndex, CTaskKill::twiTitle, szWindowTitle, 0 );
}
}
// continue the enumeration
return TRUE;
}