|
|
// *********************************************************************************
//
// Copyright (c) Microsoft Corporation
//
// Module Name:
//
// TaskList.cpp
//
// Abstract:
//
// This module implements the command-line parsing the displaying the tasks
// information current running on local and remote systems
//
// Syntax:
// ------
// TaskList.exe [-s server [-u username [-p password]]]
// [-fo format] [-fi filter] [-nh] [-v | -svc | -m]
//
// Author:
//
// Sunil G.V.N. Murali ([email protected]) 24-Sep-2000
//
// Revision History:
//
// Sunil G.V.N. Murali ([email protected]) 24-Sep-2000 : Created It.
//
// *********************************************************************************
#include "pch.h"
#include "wmi.h"
#include "TaskList.h"
//
// local structures
//
typedef struct __tagWindowTitles { LPWSTR lpDesk; LPWSTR lpWinsta; BOOL bFirstLoop; TARRAY arrWindows; } TWINDOWTITLES, *PTWINDOWTITLES;
//
// private functions ... prototypes
//
BOOL CALLBACK EnumWindowsProc( HWND hWnd, LPARAM lParam ); BOOL CALLBACK EnumDesktopsFunc( LPWSTR lpstr, LPARAM lParam ); BOOL CALLBACK EnumWindowStationsFunc( LPWSTR lpstr, LPARAM lParam ); BOOL CALLBACK EnumMessageWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam ); BOOL GetPerfDataBlock( HKEY hKey, LPWSTR szObjectIndex, PPERF_DATA_BLOCK* ppdb );
// ***************************************************************************
// 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
// ***************************************************************************
DWORD __cdecl _tmain( DWORD argc, LPCWSTR argv[] ) { // local variables
CTaskList tasklist;
// initialize the tasklist utility
if ( tasklist.Initialize() == FALSE ) { SHOW_MESSAGE_EX( TAG_ERROR, GetReason() ); EXIT_PROCESS( 1 ); }
// now do parse the command line options
if ( tasklist.ProcessOptions( argc, argv ) == FALSE ) { SHOW_MESSAGE_EX( TAG_ERROR, GetReason() ); EXIT_PROCESS( 1 ); }
// check whether usage has to be displayed or not
if ( tasklist.m_bUsage == TRUE ) { // show the usage of the utility
tasklist.Usage();
// quit from the utility
EXIT_PROCESS( 0 ); }
// now validate the filters and check the result of the filter validation
if ( tasklist.ValidateFilters() == FALSE ) { // invalid filter
SHOW_MESSAGE_EX( TAG_ERROR, GetReason() );
// quit from the utility
EXIT_PROCESS( 1 ); }
// connect to the server
if ( tasklist.Connect() == FALSE ) { // show the error message
SHOW_MESSAGE_EX( TAG_ERROR, GetReason() ); EXIT_PROCESS( 1 ); }
// load the data and check
if ( tasklist.LoadTasks() == FALSE ) { // show the error message
SHOW_MESSAGE_EX( TAG_ERROR, GetReason() );
// exit
EXIT_PROCESS( 1 ); }
// now show the tasks running on the machine
if ( tasklist.Show() == 0 ) { //
// no tasks were shown ... display the message
// check if this is because of any error
if ( GetLastError() != NO_ERROR ) { SHOW_MESSAGE_EX( TAG_ERROR, GetReason() ); EXIT_PROCESS( 1 ); } else { DISPLAY_MESSAGE( stderr, ERROR_NODATA_AVAILABLE ); } }
// clean exit
EXIT_PROCESS( 0 ); }
// ***************************************************************************
// Routine Description:
// connects to the remote as well as remote system's WMI
//
// Arguments:
// [ in ] pszServer : remote server name
//
// Return Value:
// TRUE : if connection is successful
// FALSE : if connection is unsuccessful
//
// ***************************************************************************
BOOL CTaskList::Connect() { // local variables
BOOL bResult = FALSE;
// release the existing auth identity structure
m_bUseRemote = FALSE; 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 );
// check the result of connection
if ( bResult == FALSE ) return FALSE;
#ifndef _WIN64
// determine the type of the platform if modules info is required
if ( m_bLocalSystem == TRUE && m_bNeedModulesInfo == TRUE ) { // 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 ( GetLastError() == WBEM_E_LOCAL_CREDENTIALS ) { CHString str; WMISaveError( WBEM_E_LOCAL_CREDENTIALS ); str.Format( L"\n%s %s", TAG_WARNING, GetReason() ); ShowMessage( stdout, str );
// get the next cursor position
if ( m_hOutput != NULL ) GetConsoleScreenBufferInfo( m_hOutput, &m_csbi ); }
// check the remote system version and its compatiblity
if ( m_bLocalSystem == FALSE ) { // check the version compatibility
DWORD dwVersion = 0; dwVersion = GetTargetVersionEx( m_pWbemServices, m_pAuthIdentity ); if ( IsCompatibleOperatingSystem( dwVersion ) == FALSE ) { SetReason( ERROR_OS_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; }
// ***************************************************************************
// Routine Description:
// initiate the enumeration
//
// Arguments:
// NONE
//
// Return Value:
// TRUE : if successful
// FALSE : if unsuccessful
//
// ***************************************************************************
BOOL CTaskList::LoadTasks() { // local variables
HRESULT hr; try { // check the services object
if ( m_pWbemServices == NULL ) { SetLastError( STG_E_UNKNOWN ); SaveLastError(); return FALSE; } // load the tasks from WMI based on generated query
SAFE_RELEASE( m_pEnumObjects ); hr = m_pWbemServices->ExecQuery( _bstr_t( WMI_QUERY_TYPE ), _bstr_t( m_strQuery ), WBEM_FLAG_RETURN_IMMEDIATELY | WBEM_FLAG_FORWARD_ONLY, NULL, &m_pEnumObjects ); // check the result of the ExecQuery
if ( FAILED( hr ) ) { WMISaveError( hr ); return FALSE; } // set the interface security and check the result
hr = SetInterfaceSecurity( m_pEnumObjects, m_pAuthIdentity ); if ( FAILED( hr ) ) { WMISaveError( hr ); return FALSE; } // 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 ( m_bLocalSystem == TRUE && m_bNeedWindowTitles == TRUE ) { // prepare the tasks list info
TWINDOWTITLES windowtitles; windowtitles.lpDesk = NULL; windowtitles.lpWinsta = NULL; windowtitles.bFirstLoop = FALSE; windowtitles.arrWindows = m_arrWindowTitles; EnumWindowStations( EnumWindowStationsFunc, ( LPARAM ) &windowtitles ); // free the memory allocated with _tcsdup string function
if ( windowtitles.lpDesk != NULL ) free( windowtitles.lpDesk ); if ( windowtitles.lpWinsta != NULL ) free( windowtitles.lpWinsta ); }
// load the extended tasks information
LoadTasksEx(); // NOTE: here we are not much bothered abt the return value
// erase the status messages
PrintProgressMsg( m_hOutput, NULL, m_csbi ); } catch( _com_error& e ) { WMISaveError( e ); return FALSE; } // return success
return TRUE; }
// ***************************************************************************
// Routine Description:
//
// Arguments:
//
// Return Value:
//
// ***************************************************************************
BOOL CTaskList::LoadTasksEx() { // local variables
BOOL bResult = FALSE;
// init
m_bCloseConnection = FALSE;
// 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 ( m_bLocalSystem == FALSE && m_pAuthIdentity != NULL ) { // 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 ( m_strUserName.GetLength() != 0 ) 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 ( dwConnect != NO_ERROR ) { // 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 ( dwConnect != ERROR_SESSION_CREDENTIAL_CONFLICT ) { // 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 ( pwszUser == NULL || pwszPassword == NULL ) m_bCloseConnection = FALSE; }
try { // connect to the remote system's winstation
bResult = TRUE; m_hServer = SERVERNAME_CURRENT; if ( m_bLocalSystem == FALSE ) { // sub-local variables
LPWSTR pwsz = NULL;
// connect to the winsta and check the result
pwsz = m_strUNCServer.GetBuffer( m_strUNCServer.GetLength() ); m_hServer = WinStationOpenServerW( pwsz );
// proceed furthur only if winstation of the remote system is successfully opened
if ( m_hServer == NULL ) bResult = FALSE; } } catch( ... ) { SetLastError( E_OUTOFMEMORY ); SaveLastError(); return FALSE; }
// prepare to get the user context info .. if needed
if ( m_bNeedUserContextInfo == TRUE && bResult == TRUE ) { // get all the process details
m_bIsHydra = FALSE; bResult = WinStationGetAllProcesses( m_hServer, GAP_LEVEL_BASIC, &m_ulNumberOfProcesses, (PVOID*) &m_pProcessInfo ); // check the result
if ( bResult == FALSE ) { // Maybe a Hydra 4 server ?
// Check the return code indicating that the interface is not available.
if ( GetLastError() == RPC_S_PROCNUM_OUT_OF_RANGE ) { // The new interface is not known
// It must be a Hydra 4 server
// try with the old interface
bResult = WinStationEnumerateProcesses( m_hServer, (PVOID*) &m_pProcessInfo );
// check the result of enumeration
if ( bResult == TRUE ) m_bIsHydra = TRUE; } } }
// check whether we need services info or not
if ( m_bNeedServicesInfo == TRUE ) { // load the services
bResult = LoadServicesInfo();
// check the result
if ( bResult == FALSE ) return FALSE; }
// check whether we need modules info or not
if ( m_bNeedModulesInfo == TRUE ) { // load the modules information
bResult = LoadModulesInfo();
// check the result
if ( bResult == FALSE ) return FALSE; }
// return
return TRUE; }
// ***************************************************************************
// Routine Description:
//
// Arguments:
//
// Return Value:
//
// ***************************************************************************
BOOL CTaskList::LoadModulesInfo() { // local variables
HKEY hKey; LONG lReturn = 0; BOOL bResult = FALSE; BOOL bImagesObject = FALSE; BOOL bAddressSpaceObject = FALSE; PPERF_OBJECT_TYPE pot = NULL; PPERF_COUNTER_DEFINITION pcd = 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 ( m_bNeedModulesInfo == FALSE || m_bLocalSystem == TRUE ) return TRUE;
// display the status message
PrintProgressMsg( m_hOutput, MSG_MODULESINFO, m_csbi );
// open the remote system performance data key
lReturn = RegConnectRegistry( m_strUNCServer, HKEY_PERFORMANCE_DATA, &hKey ); if ( lReturn != ERROR_SUCCESS ) { SetLastError( lReturn ); SaveLastError(); return FALSE; }
// get the performance object ( images )
bResult = GetPerfDataBlock( hKey, L"740", &m_pdb ); if ( bResult == FALSE ) { // close the registry key and return
RegCloseKey( hKey ); return FALSE; }
// check the validity of the perf block
if ( StringCompare( m_pdb->Signature, L"PERF", FALSE, 4 ) != 0 ) { // close the registry key and return
RegCloseKey( hKey ); // set the error message
SetLastError( 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 ( pot->ObjectNameTitleIndex == 740 ) bImagesObject = TRUE; else if ( pot->ObjectNameTitleIndex == 786 ) bAddressSpaceObject = TRUE;
// move to the next object
if( pot->TotalByteLength != 0 ) pot = ( (PPERF_OBJECT_TYPE) ((PBYTE) pot + pot->TotalByteLength)); }
// check whether we got the needed objects or not
if ( bImagesObject == FALSE || bAddressSpaceObject == FALSE ) { SetLastError( ERROR_ACCESS_DENIED ); SaveLastError(); return FALSE; }
// return
return TRUE; }
// ***************************************************************************
// Routine Description:
//
// Arguments:
//
// Return Value:
//
// ***************************************************************************
BOOL CTaskList::LoadUserNameFromWinsta( CHString& strDomain, CHString& strUserName ) { // 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 ( m_pProcessInfo == NULL ) return FALSE;
try { // allocate buffers
dwUserLength = 128; dwDomainLength = 128; pwszUser = strUserName.GetBufferSetLength( dwUserLength ); pwszDomain = strDomain.GetBufferSetLength( dwDomainLength ); } catch( ... ) { SetLastError( E_OUTOFMEMORY ); SaveLastError(); return FALSE; }
//
// find for the appropriate the process
pSid = NULL; if ( m_bIsHydra == FALSE ) { // 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 ...
//
// sub-local variables
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( pspi->NextEntryOffset == 0 ) 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( pcpi->MagicNumber == CITRIX_PROCESS_INFO_MAGIC ) pSid = pcpi->ProcessSid; }
// check the sid value
if ( pSid == NULL ) { // SPECIAL CASE:
// -------------
// PID -> 0 will have a special hard coded user name info
if ( m_dwProcessId == 0 ) { bResult = TRUE; lstrcpynW( pwszUser, PID_0_USERNAME, dwUserLength ); lstrcpynW( pwszDomain, PID_0_DOMAIN, dwDomainLength ); }
// release the buffer
strDomain.ReleaseBuffer(); strUserName.ReleaseBuffer(); return bResult; }
// determine the server
pwszServer = NULL; if ( m_bLocalSystem == FALSE ) 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();
// return the result
return bResult; }
// ***************************************************************************
// Routine Description:
//
// Arguments:
//
// Return Value:
//
// ***************************************************************************
BOOL CTaskList::LoadServicesInfo() { // 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 ( m_bNeedServicesInfo == FALSE ) return TRUE;
// display the status message
PrintProgressMsg( m_hOutput, MSG_SERVICESINFO, m_csbi );
// determine the server
pwszServer = NULL; if ( m_bLocalSystem == FALSE ) pwszServer = m_strUNCServer;
// Connect to the service controller and check the result
hScm = OpenSCManager( pwszServer, NULL, SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE ); if ( hScm == NULL) { // 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 ( ++dw <= 2 ) { // set the size
dwSize += dwExtraNeeded;
// allocate memory for storing services information
pInfo = ( LPENUM_SERVICE_STATUS_PROCESS ) __calloc( 1, dwSize ); if ( pInfo == NULL ) { // failed in allocating needed memory ... error
SetLastError( 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 ( bResult ) { // successfully enumerated all the services information
break; // jump out of the loop
}
// first free the allocated memory
__free( pInfo );
// now lets look at what is the error
if ( GetLastError() == ERROR_MORE_DATA ) { // 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
} }
// check whether there any services or not ... if services count is zero, free the memory
if ( m_dwServicesCount == 0 ) { // no services exists
__free( pInfo ); } else { // set the local pointer to the out parameter
m_pServicesInfo = pInfo; }
// inform success
return TRUE; }
// ***************************************************************************
// Routine Description:
//
// Arguments:
//
// Return Value:
//
// ***************************************************************************
BOOL GetPerfDataBlock( HKEY hKey, LPWSTR pwszObjectIndex, PPERF_DATA_BLOCK* ppdb ) { // local variables
LONG lReturn = 0; DWORD dwBytes = 0; BOOL bResult = FALSE;
// check the input parameters
if ( pwszObjectIndex == NULL || ppdb == NULL ) return FALSE;
// allocate memory for PERF_DATA_BLOCK
dwBytes = 32 * 1024; // initially allocate for 32 K
*ppdb = (PPERF_DATA_BLOCK) HeapAlloc( GetProcessHeap(), 0, dwBytes ); if( *ppdb == NULL ) { SetLastError( E_OUTOFMEMORY ); SaveLastError(); return FALSE; }
// get performance data on passed Object
lReturn = RegQueryValueEx( hKey, pwszObjectIndex, NULL, NULL, (LPBYTE) *ppdb, &dwBytes ); while( lReturn == ERROR_MORE_DATA ) { // increase memory by 8 K
dwBytes += 8192;
// allocated memory is too small reallocate new memory
*ppdb = (PPERF_DATA_BLOCK) HeapReAlloc( GetProcessHeap(), 0, *ppdb, dwBytes ); if( *ppdb == NULL ) { SetLastError( 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 ( lReturn != ERROR_SUCCESS ) { if ( *ppdb != NULL) { HeapFree( GetProcessHeap(), 0, *ppdb ); *ppdb = NULL; }
// save the error info
bResult = FALSE; SetLastError( lReturn ); SaveLastError(); }
// return the result
return bResult; }
// ***************************************************************************
// 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
//
// ***************************************************************************
BOOL CALLBACK EnumWindowStationsFunc( LPTSTR lpstr, LPARAM lParam ) { // local variables
HWINSTA hWinSta = NULL; HWINSTA hwinstaSave = NULL; PTWINDOWTITLES pWndTitles = ( PTWINDOWTITLES ) lParam;
// check the input arguments
if ( lpstr == NULL || lParam == NULL ) 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, WINSTA_ENUMERATE | WINSTA_ENUMDESKTOPS ); if ( hWinSta == NULL ) { // failed in getting the process window station
SaveLastError(); return FALSE; } else { // change the context to the new workstation
if ( hWinSta != hwinstaSave && SetProcessWindowStation( hWinSta ) == FALSE ) { // failed in changing the context
SaveLastError(); return FALSE; }
// release the memory allocated for earlier window station
if ( pWndTitles->lpWinsta != NULL ) { free( pWndTitles->lpWinsta ); pWndTitles->lpWinsta = NULL; }
// store the window station name
pWndTitles->lpWinsta = _tcsdup( lpstr ); if ( pWndTitles->lpWinsta == NULL ) { SetLastError( E_OUTOFMEMORY ); SaveLastError(); 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; }
// ***************************************************************************
// 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
//
// ***************************************************************************
BOOL CALLBACK EnumDesktopsFunc( LPTSTR lpstr, LPARAM lParam ) { // local variables
HDESK hDesk = NULL; HDESK hdeskSave = NULL; PTWINDOWTITLES pWndTitles = ( PTWINDOWTITLES )lParam;
// check the input arguments
if ( lpstr == NULL || lParam == NULL ) 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, DESKTOP_ENUMERATE ); if ( hDesk == NULL ) { // failed in getting the process desktop
SaveLastError(); return FALSE; } else { // change the context to the new desktop
if ( hDesk != hdeskSave && SetThreadDesktop( hDesk ) == FALSE ) { // failed in changing the context
SaveLastError(); // ?? return FALSE; -- needs to uncommented
}
// release the memory allocated for earlier window station
if ( pWndTitles->lpDesk != NULL ) { free( pWndTitles->lpDesk ); pWndTitles->lpDesk = NULL; }
// store the desktop name
pWndTitles->lpDesk = _tcsdup( lpstr ); if ( pWndTitles->lpDesk == NULL ) { SetLastError( E_OUTOFMEMORY ); SaveLastError(); 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; }
// ***************************************************************************
// 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
// ***************************************************************************
BOOL CALLBACK EnumMessageWindows( WNDENUMPROC lpEnumFunc, LPARAM lParam ) { // local variables
HWND hWnd = NULL; BOOL bResult = FALSE;
// check the input arguments
if ( lpEnumFunc == NULL || lParam == NULL ) 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 ( hWnd != NULL ) { // 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 ( bResult == FALSE ) { // terminate the enumeration
break; } } } while ( hWnd != NULL );
// return the enumeration result
return bResult; }
// ***************************************************************************
// 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
// ***************************************************************************
BOOL CALLBACK EnumWindowsProc( HWND hWnd, LPARAM lParam ) { // local variables
LONG lIndex = 0; DWORD dwPID = 0; BOOL bVisible = FALSE; TARRAY arrWindows = NULL; PTWINDOWTITLES pWndTitles = NULL; __MAX_SIZE_STRING szWindowTitle = NULL_STRING;
// check the input arguments
if ( hWnd == NULL || lParam == NULL ) return FALSE; // get the values from the lParam
pWndTitles = ( PTWINDOWTITLES ) lParam; arrWindows = pWndTitles->arrWindows;
// get the processid for this window
if ( GetWindowThreadProcessId( hWnd, &dwPID ) == 0 ) { // 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 ( bVisible == FALSE && pWndTitles->bFirstLoop == TRUE ) 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 ( GetWindow(hWnd, GW_OWNER) != NULL ) { // 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, CTaskList::twiProcessId, dwPID ); if ( lIndex == -1 ) { // window for this process is not there ... save it
lIndex = DynArrayAppendRow( arrWindows, CTaskList::twiCOUNT ); } else { // check whether window details already exists or not
if ( DynArrayItemAsHandle2( arrWindows, lIndex, CTaskList::twiHandle ) != NULL ) lIndex = -1; // window details already exists
}
// check if window details has to be saved or not ... if needed save them
if ( lIndex != -1 ) { DynArraySetDWORD2( arrWindows, lIndex, CTaskList::twiProcessId, dwPID ); DynArraySetHandle2( arrWindows, lIndex, CTaskList::twiHandle, hWnd ); DynArraySetString2( arrWindows, lIndex, CTaskList::twiWinSta, pWndTitles->lpWinsta, 0 ); DynArraySetString2( arrWindows, lIndex, CTaskList::twiDesktop, pWndTitles->lpDesk, 0 );
// get and save the window title
if ( GetWindowText( hWnd, szWindowTitle, SIZE_OF_ARRAY( szWindowTitle ) ) != 0 ) DynArraySetString2( arrWindows, lIndex, CTaskList::twiTitle, szWindowTitle, 0 ); } // continue the enumeration
return TRUE; }
// ***************************************************************************
// Routine Description:
//
// Arguments:
//
// Return Value:
//
// ***************************************************************************
VOID PrintProgressMsg( HANDLE hOutput, LPCWSTR pwszMsg, const CONSOLE_SCREEN_BUFFER_INFO& csbi ) { // local variables
COORD coord; DWORD dwSize = 0; WCHAR wszSpaces[ 80 ] = L"";
// check the handle. if it is null, it means that output is being redirected. so return
if ( hOutput == NULL ) return;
// set the cursor position
coord.X = 0; coord.Y = csbi.dwCursorPosition.Y;
// first erase contents on the current line
ZeroMemory( wszSpaces, 80 ); SetConsoleCursorPosition( hOutput, coord ); WriteConsoleW( hOutput, Replicate( wszSpaces, L"", 79 ), 79, &dwSize, NULL );
// now display the message ( if exists )
SetConsoleCursorPosition( hOutput, coord ); if ( pwszMsg != NULL ) WriteConsoleW( hOutput, pwszMsg, lstrlen( pwszMsg ), &dwSize, NULL ); }
|