CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 17
  1. #1
    Join Date
    May 2015
    Posts
    536

    Process info display

    Hello,

    I need to display the information of a process in c++. (ie number of threads in c++ , belonging to a process etc) in windows

    I am not system level programmer , coming from linux user level prog.

    I tried to go through the windows documentation and came up with the following experiment program, before trying to fit in into the actual code.

    I tried to create a calculator process in the main(), and then pass that process Id to a function (I copied from the microsoft website). In this program, it tries to loop through all the process. It then compares the process Id with the passed process Id.

    It uses the if( !Process32First( hProcessSnap, &pe32 ) ), to get the first process.

    It then traverses the process list . It opens each process with the
    hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID );

    But somehow the OpenProcess is always failing.

    Iam getting the following output.

    Waiting on process for 20 seconds..

    WARNING: OpenProcess failed with error 87 (The parameter is incorrect)
    WARNING: OpenProcess failed with error 5 (Access is denied)
    WARNING: OpenProcess failed with error 5 (Access is denied)
    WARNING: OpenProcess failed with error 5 (Access is denied)
    WARNING: OpenProcess failed with error 5 (Access is denied)
    WARNING: OpenProcess failed with error 5 (Access is denied)
    WARNING: OpenProcess failed with error 5 (Access is denied)
    WARNING: OpenProcess failed with error 5 (Access is denied)
    WARNING: OpenProcess failed with error 5 (Access is denied)
    WARNING: OpenProcess failed with error 5 (Access is denied)
    WARNING: OpenProcess failed with error 5 (Access is denied)
    WARNING: OpenProcess failed with error 5 (Access is denied)
    WARNING: OpenProcess failed with error 5 (Access is denied)
    WARNING: OpenProcess failed with error 5 (Access is denied)
    WARNING: OpenProcess failed with error 5 (Access is denied)
    WARNING: OpenProcess failed with error 5 (Access is denied)

    Code:
    #include <iostream>
    using namespace std;
    
    #include <Windows.h>
    
    #include <tlhelp32.h>
    
    //BOOL ListProcessThreads( DWORD dwOwnerPID );
    //void printError( TCHAR const* msg );
    
    #include <tchar.h>
    #include <stdio.h>
    
    //  Forward declarations:
    BOOL GetProcessList( DWORD cPid );
    BOOL ListProcessModules( DWORD dwPID );
    BOOL ListProcessThreads( DWORD dwOwnerPID );
    void printError( TCHAR const* msg );
    
    //int main( void )
    //{
    //	GetProcessList( );
    //	return 0;
    //}
    
    int main ()
    {
    	STARTUPINFO si = {};
    	si.cb = sizeof si;
    
    	PROCESS_INFORMATION pi = {};
    	const TCHAR* target = _T("C:\\Windows\\WinSxS\\wow64_microsoft-windows-calc_31bf3856ad364e35_10.0.19041.1_none_6a03b910ee7a4073\\calc.exe");
    
    	if ( !CreateProcess(target, 0, 0, FALSE, 0, 0, 0, 0, &si, &pi) )
    	{
    		cerr << "CreateProcess failed (" << GetLastError() << ").\n";
    	}
    	else
    	{
    		FILETIME ftime, fsys, fuser;
    
    		cout << "Waiting on process for 20 seconds.." << endl;
    
    		//ListProcessThreads(pi.hProcess);
    		//ListProcessThreads(GetCurrentProcessId() );
    
    		//ListProcessThreads(pi.dwProcessId);
    		WaitForSingleObject(pi.hProcess, 20 * 1000);
    
    		//GetProcessTimes(pi.hProcess, &ftime, &ftime, &fsys, &fuser);
    		GetProcessList(pi.dwProcessId);
    		/*
    		if ( TerminateProcess(pi.hProcess, 0) ) // Evil
    		cout << "Process terminated!";
    		*/
    		if ( PostThreadMessage(pi.dwThreadId, WM_QUIT, 0, 0) ) // Good
    			cout << "Request to terminate process has been sent!";
    
    		CloseHandle(pi.hProcess);
    		CloseHandle(pi.hThread);
    	}
    
    	cin.sync();
    	cin.ignore();
    
    	return 0;
    }
    BOOL GetProcessList( DWORD cPid)
    {
    	HANDLE hProcessSnap;
    	HANDLE hProcess;
    	PROCESSENTRY32 pe32;
    	DWORD dwPriorityClass;
    
    	// Take a snapshot of all processes in the system.
    	hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
    	if( hProcessSnap == INVALID_HANDLE_VALUE )
    	{
    		printError( TEXT("CreateToolhelp32Snapshot (of processes)") );
    		return( FALSE );
    	}
    
    	// Set the size of the structure before using it.
    	pe32.dwSize = sizeof( PROCESSENTRY32 );
    
    	// Retrieve information about the first process,
    	// and exit if unsuccessful
    	if( !Process32First( hProcessSnap, &pe32 ) )
    	{
    		printError( TEXT("Process32First") ); // show cause of failure
    		CloseHandle( hProcessSnap );          // clean the snapshot object
    		return( FALSE );
    	}
    
    	// Now walk the snapshot of processes, and
    	// display information about each process in turn
    	do
    	{
    		//_tprintf( TEXT("\n\n=====================================================" ));
    		//_tprintf( TEXT("\nPROCESS NAME:  %s"), pe32.szExeFile );
    		//_tprintf( TEXT("\n-------------------------------------------------------" ));
    
    		// Retrieve the priority class.
    		dwPriorityClass = 0;
    
    		
    		hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID );
    		if( hProcess == NULL )
    			printError( TEXT("OpenProcess") );
    		else
    		{
    			dwPriorityClass = GetPriorityClass( hProcess );
    			if( !dwPriorityClass )
    				printError( TEXT("GetPriorityClass") );
    			CloseHandle( hProcess );
    		}
    
    
    		if(cPid == pe32.th32ProcessID)
    		{
    			_tprintf( TEXT("\n  Process ID        = 0x%08X"), pe32.th32ProcessID );
    			_tprintf( TEXT("\n  Thread count      = %d"),   pe32.cntThreads );
    			_tprintf( TEXT("\n  Parent process ID = 0x%08X"), pe32.th32ParentProcessID );
    			_tprintf( TEXT("\n  Priority base     = %d"), pe32.pcPriClassBase );
    			if( dwPriorityClass )
    				_tprintf( TEXT("\n  Priority class    = %d"), dwPriorityClass );
    
    			// List the modules and threads associated with this process
    			ListProcessModules( pe32.th32ProcessID );
    			ListProcessThreads( pe32.th32ProcessID );
    
    			break;
    		}
    
    	} while( Process32Next( hProcessSnap, &pe32 ) );
    
    	CloseHandle( hProcessSnap );
    	return( TRUE );
    }
    
    
    BOOL ListProcessModules( DWORD dwPID )
    {
    	HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
    	MODULEENTRY32 me32;
    
    	// Take a snapshot of all modules in the specified process.
    	hModuleSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, dwPID );
    	if( hModuleSnap == INVALID_HANDLE_VALUE )
    	{
    		printError( TEXT("CreateToolhelp32Snapshot (of modules)") );
    		return( FALSE );
    	}
    
    	// Set the size of the structure before using it.
    	me32.dwSize = sizeof( MODULEENTRY32 );
    
    	// Retrieve information about the first module,
    	// and exit if unsuccessful
    	if( !Module32First( hModuleSnap, &me32 ) )
    	{
    		printError( TEXT("Module32First") );  // show cause of failure
    		CloseHandle( hModuleSnap );           // clean the snapshot object
    		return( FALSE );
    	}
    
    	// Now walk the module list of the process,
    	// and display information about each module
    	do
    	{
    		_tprintf( TEXT("\n\n     MODULE NAME:     %s"),   me32.szModule );
    		_tprintf( TEXT("\n     Executable     = %s"),     me32.szExePath );
    		_tprintf( TEXT("\n     Process ID     = 0x%08X"),         me32.th32ProcessID );
    		_tprintf( TEXT("\n     Ref count (g)  = 0x%04X"),     me32.GlblcntUsage );
    		_tprintf( TEXT("\n     Ref count (p)  = 0x%04X"),     me32.ProccntUsage );
    		_tprintf( TEXT("\n     Base address   = 0x%08X"), (DWORD) me32.modBaseAddr );
    		_tprintf( TEXT("\n     Base size      = %d"),             me32.modBaseSize );
    
    	} while( Module32Next( hModuleSnap, &me32 ) );
    
    	CloseHandle( hModuleSnap );
    	return( TRUE );
    }
    
    BOOL ListProcessThreads( DWORD dwOwnerPID ) 
    { 
    	HANDLE hThreadSnap = INVALID_HANDLE_VALUE; 
    	THREADENTRY32 te32; 
    
    	// Take a snapshot of all running threads  
    	hThreadSnap = CreateToolhelp32Snapshot( TH32CS_SNAPTHREAD, 0 ); 
    	if( hThreadSnap == INVALID_HANDLE_VALUE ) 
    		return( FALSE ); 
    
    	// Fill in the size of the structure before using it. 
    	te32.dwSize = sizeof(THREADENTRY32); 
    
    	// Retrieve information about the first thread,
    	// and exit if unsuccessful
    	if( !Thread32First( hThreadSnap, &te32 ) ) 
    	{
    		printError( TEXT("Thread32First") ); // show cause of failure
    		CloseHandle( hThreadSnap );          // clean the snapshot object
    		return( FALSE );
    	}
    
    	// Now walk the thread list of the system,
    	// and display information about each thread
    	// associated with the specified process
    	do 
    	{ 
    		if( te32.th32OwnerProcessID == dwOwnerPID )
    		{
    			_tprintf( TEXT("\n\n     THREAD ID      = 0x%08X"), te32.th32ThreadID ); 
    			_tprintf( TEXT("\n     Base priority  = %d"), te32.tpBasePri ); 
    			_tprintf( TEXT("\n     Delta priority = %d"), te32.tpDeltaPri ); 
    			_tprintf( TEXT("\n"));
    		}
    	} while( Thread32Next(hThreadSnap, &te32 ) ); 
    
    	CloseHandle( hThreadSnap );
    	return( TRUE );
    }
    
    void printError( TCHAR const* msg )
    {
    	DWORD eNum;
    	TCHAR sysMsg[256];
    	TCHAR* p;
    
    	eNum = GetLastError( );
    	FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
    		NULL, eNum,
    		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
    		sysMsg, 256, NULL );
    
    	// Trim the end of the line and terminate it with a null
    	p = sysMsg;
    	while( ( *p > 31 ) || ( *p == 9 ) )
    		++p;
    	do { *p-- = 0; } while( ( p >= sysMsg ) &&
    		( ( *p == '.' ) || ( *p < 33 ) ) );
    
    	// Display the message
    	_tprintf( TEXT("\n  WARNING: %s failed with error %d (%s)"), msg, eNum, sysMsg );
    }
    Last edited by pdk5; March 23rd, 2025 at 07:08 AM.

  2. #2
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,631

    Re: Process info display

    PROCESS_ALL_ACCESS must be the cause of Access denied. The access level is way too high for an average app, so rejected. (See MSDN)

    An option might be running your process with elevated privileges, but still requesting for a reasonable access level won't hurt anybody.

    GetPriorityClass says:

    The handle must have the PROCESS_QUERY_INFORMATION or PROCESS_QUERY_LIMITED_INFORMATION access right.
    BTW, why don't you just cut that priority class stuff off?
    Last edited by Igor Vartanov; March 23rd, 2025 at 12:15 PM.
    Best regards,
    Igor

  3. #3
    Join Date
    May 2015
    Posts
    536

    Re: Process info display

    Thankyou very much Igor. Sorry for delay, somehow the website was not reachable for me yesterday (!)

    Im not windows internal programmer, so it would have been helpful with sample code. (Sorry for asking too much. Ofcourse, I'll try to do my homework)

  4. #4
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,903

    Re: Process info display

    Code:
    hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID );
    For this to work, the process security descriptor for the requested process must allow this process the required access. This is not so by default. Or your process needs to have SeDebugPrivilege privilege - which requires admin access to set, You need to determine the minimum access security required for your program and open the process for that level of process access. If this is greater than the available process security then you're probably going to need SeDebugPrivilege and to run the program as an administrator.

    GetPriorityClass() requires PROCESS_QUERY_INFORMATION or PROCESS_QUERY_LIMITED_INFORMATION privilege. So you should first try to acquire this privilege. See https://learn.microsoft.com/en-us/wi...ges-in-a-token
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  5. #5
    Join Date
    May 2015
    Posts
    536

    Re: Process info display

    Quote Originally Posted by 2kaud View Post
    Code:
    hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID );
    For this to work, the process security descriptor for the requested process must allow this process the required access. This is not so by default. Or your process needs to have SeDebugPrivilege privilege - which requires admin access to set, You need to determine the minimum access security required for your program and open the process for that level of process access. If this is greater than the available process security then you're probably going to need SeDebugPrivilege and to run the program as an administrator.

    GetPriorityClass() requires PROCESS_QUERY_INFORMATION or PROCESS_QUERY_LIMITED_INFORMATION privilege. So you should first try to acquire this privilege. See https://learn.microsoft.com/en-us/wi...ges-in-a-token
    Thankyou very much kaud for the help .I;ll go through the link.

    But this app when the customer runs, they might not get the access (unless he runs in with high prio as admin). So I think, the logging functionality I am going to add, will only be enabled based on priority .

  6. #6
    Join Date
    May 2015
    Posts
    536

    Re: Process info display

    issues Im facing

    1. Snapshot Process, does not show me the current process
    2. If i open the process in the same function, the OpenProcess API succeeds. But fails in another function, where I try to acces process via a snapshot

    In the BOOL GetProcessList( DWORD cPid), in the while loop, the none of the snapshot process ids match the one passed in.
    Code:
    int main ()
    {
    	STARTUPINFO si = {};
    	si.cb = sizeof si;
    
    	PROCESS_INFORMATION pi = {};
    	const TCHAR* target = _T("C:\\Windows\\WinSxS\\wow64_microsoft-windows-calc_31bf3856ad364e35_10.0.19041.1_none_6a03b910ee7a4073\\calc.exe");
    
    	if ( !CreateProcess(target, 0, 0, FALSE, 0, 0, 0, 0, &si, &pi) )
    	{
    		cerr << "CreateProcess failed (" << GetLastError() << ").\n";
    	}
    	else
    	{
    		FILETIME ftime, fsys, fuser;
    
    		cout << "Waiting on process for 20 seconds.." << endl;
    
    		//ListProcessThreads(pi.hProcess);
    		//ListProcessThreads(GetCurrentProcessId() );
    
    
    	        // This opens handle 
    		HANDLE hProcess = OpenProcess(PROCESS_VM_WRITE | PROCESS_VM_READ | PROCESS_VM_OPERATION , NULL,  pi.dwProcessId);
    
    		GetProcessList(pi.dwProcessId);
    		// 
    		//ListProcessThreads(pi.dwProcessId);
    		WaitForSingleObject(pi.hProcess, 20 * 1000);
    
    		//HANDLE hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pi.dwProcessId );
    		/*
    		if ( TerminateProcess(pi.hProcess, 0) ) // Evil
    		cout << "Process terminated!";
    		*/
    		if ( PostThreadMessage(pi.dwThreadId, WM_QUIT, 0, 0) ) // Good
    			cout << "Request to terminate process has been sent!";
    
    		CloseHandle(pi.hProcess);
    		CloseHandle(pi.hThread);
    	}
    
    	cin.sync();
    	cin.ignore();
    
    	return 0;
    }
    
    BOOL GetProcessList( DWORD cPid)
    {
    	HANDLE hProcessSnap;
    	HANDLE hProcess;
    	PROCESSENTRY32 pe32;
    	DWORD dwPriorityClass;
    
        // This open fails
    	hProcess = OpenProcess(PROCESS_VM_WRITE | PROCESS_VM_READ | PROCESS_VM_OPERATION , NULL,  cPid);
    
    	// Take a snapshot of all processes in the system.
    	hProcessSnap = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 );
    	if( hProcessSnap == INVALID_HANDLE_VALUE )
    	{
    		printError( TEXT("CreateToolhelp32Snapshot (of processes)") );
    		return( FALSE );
    	}
    
    	// Set the size of the structure before using it.
    	pe32.dwSize = sizeof( PROCESSENTRY32 );
    
    	// Retrieve information about the first process,
    	// and exit if unsuccessful
    	if( !Process32First( hProcessSnap, &pe32 ) )
    	{
    		printError( TEXT("Process32First") ); // show cause of failure
    		CloseHandle( hProcessSnap );          // clean the snapshot object
    		return( FALSE );
    	}
    
    	// Now walk the snapshot of processes, and
    	// display information about each process in turn
    	do
    	{
    		//_tprintf( TEXT("\n\n=====================================================" ));
    		//_tprintf( TEXT("\nPROCESS NAME:  %s"), pe32.szExeFile );
    		//_tprintf( TEXT("\n-------------------------------------------------------" ));
    
    		// Retrieve the priority class.
    		dwPriorityClass = 0;
    
    		
    		HANDLE hProcess = OpenProcess(PROCESS_VM_WRITE | PROCESS_VM_READ | PROCESS_VM_OPERATION , NULL,  pe32.th32ProcessID);
    		//hProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, pe32.th32ProcessID );
    		if( hProcess == NULL )
    			printError( TEXT("OpenProcess") );
    		else
    		{
    
                                     // Never hits this , ie snapshot doesnot have the current process
    			if(cPid == pe32.th32ProcessID)
    			{
    				_tprintf( TEXT("\n  Process ID        = 0x%08X"), pe32.th32ProcessID );
    				_tprintf( TEXT("\n  Thread count      = %d"),   pe32.cntThreads );
    				_tprintf( TEXT("\n  Parent process ID = 0x%08X"), pe32.th32ParentProcessID );
    				_tprintf( TEXT("\n  Priority base     = %d"), pe32.pcPriClassBase );
    				if( dwPriorityClass )
    					_tprintf( TEXT("\n  Priority class    = %d"), dwPriorityClass );
    
    				dwPriorityClass = GetPriorityClass( hProcess );
    				//if( !dwPriorityClass )
    				//	printError( TEXT("GetPriorityClass") );
    				CloseHandle( hProcess );
    
    
    				break;
    			}
    
    		}
    
    
    
    
    	} while( Process32Next( hProcessSnap, &pe32 ) );
    
    	CloseHandle( hProcessSnap );
    	return( TRUE );
    }

    Eventhough for me, I used the snapshot of threads functionality to get the info, I wanted to know why this process snapshot doesnot work !
    Last edited by pdk5; March 26th, 2025 at 05:16 AM.

  7. #7
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,903

    Re: Process info display

    When you call OpenProcess() you are not testing the return value for NULL. When you call ANY of the os api functions you need to always test for api failure. If an api call fails then you use GetLastError() to obtain the error code for the failure.
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  8. #8
    Join Date
    May 2015
    Posts
    536

    Re: Process info display

    Thankyou very much kaud for inputs. OK I'll do that.
    Btw, this I coded for my own understanding and I tried to check return via debugger (it was not NULL)

  9. #9
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,903

    Re: Process info display

    BTW, why are you trying to open the same process twice? and why try to open with PROCESS_VM_WRITE?
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  10. #10
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,903

    Re: Process info display

    I'd suggest you first start small, get something working and then build on that with testing at each new stage. For a starter, this code will just enumerate all the processes:

    Code:
    #define WIN32_LEAN_AND_MEAN
    #define NOMINMAX
    #define _CRT_SECURE_NO_WARNINGS
    #define _USE_MATH_DEFINES
    
    #include <Windows.h>
    #include <tlhelp32.h>
    #include <tchar.h>
    #include <stdio.h>
    
    void printError(TCHAR const* msg);
    BOOL DisplayProcesses();
    
    int main() {
    	DisplayProcesses();
    }
    
    BOOL DisplayProcesses() {
    	// Take a snapshot of all processes in the system.
    	auto hProcessSnap { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) };
    
    	if (hProcessSnap == INVALID_HANDLE_VALUE) {
    		printError(TEXT("CreateToolhelp32Snapshot (of processes)"));
    		return FALSE;
    	}
    
    	PROCESSENTRY32 pe32 { sizeof(PROCESSENTRY32) };
    
    	// Retrieve information about the first process,
    	// and exit if unsuccessful
    	if (!Process32First(hProcessSnap, &pe32)) {
    		printError(TEXT("Process32First")); // show cause of failure
    		CloseHandle(hProcessSnap);          // clean the snapshot object
    		return(FALSE);
    	}
    
    	// Now walk the snapshot of processes, and
    	// display information about each process in turn
    	do {
    		_tprintf(TEXT("\n  Process name      = %s"), pe32.szExeFile);
    		_tprintf(TEXT("\n  Process ID        = 0x%08X"), pe32.th32ProcessID);
    		_tprintf(TEXT("\n  Thread count      = %d"), pe32.cntThreads);
    		_tprintf(TEXT("\n  Parent process ID = 0x%08X"), pe32.th32ParentProcessID);
    		_tprintf(TEXT("\n  Priority base     = %d"), pe32.pcPriClassBase);
    	} while (Process32Next(hProcessSnap, &pe32));
    
    	CloseHandle(hProcessSnap);
    	return TRUE;
    }
    
    void printError(TCHAR const* msg) {
    	const auto eNum { GetLastError() };
    	TCHAR sysMsg[256];
    
    	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
    		NULL, eNum,
    		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
    		sysMsg, sizeof(sysMsg), NULL);
    
    	// Trim the end of the line and terminate it with a null
    	auto p { sysMsg };
    
    	while ((*p >= ' ') || (*p == 9))
    		++p;
    
    	do *p-- = 0;
    	while ((p >= sysMsg) && ((*p == '.') || (*p <= ' ')));
    
    	// Display the message
    	_tprintf(TEXT("\n  WARNING: %s failed with error %d (%s)"), msg, eNum, sysMsg);
    }
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  11. #11
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,903

    Re: Process info display

    This is an extension to the above code. This will start the program testc and then obtain process info about this program. Note that the program for which process data is to be obtained must not run and then terminate - otherwise it won't be picked up by the snapshot.

    Code:
    #define WIN32_LEAN_AND_MEAN
    #define NOMINMAX
    #define _CRT_SECURE_NO_WARNINGS
    #define _USE_MATH_DEFINES
    
    #include <Windows.h>
    #include <tlhelp32.h>
    #include <tchar.h>
    #include <stdio.h>
    
    void printError(TCHAR const* msg);
    BOOL DisplayProcesses(DWORD pid = 0);
    
    int main() {
    	const TCHAR* target { _T("C:\\myprogs\\testc.exe") };
    	STARTUPINFO si {sizeof(STARTUPINFO)};
    	PROCESS_INFORMATION pi {};
    
    	if (!CreateProcess(target, 0, 0, FALSE, 0, 0, 0, 0, &si, &pi))
    		return printError("CreateProcess failed"), 1;
    
    	const auto hProcess { OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_TERMINATE, NULL, pi.dwProcessId) };
    
    	if (hProcess != NULL) {
    		if (!DisplayProcesses(pi.dwProcessId))
    			_tprintf(TEXT("Process not found\n"));
    
    		if (TerminateProcess(hProcess, 0) == 0)
    			printError("TerminateProcess failed");
    
    		CloseHandle(hProcess);
    	} else
    		printError("OpenProcess failed");
    
    	CloseHandle(pi.hThread);
    	CloseHandle(pi.hProcess);
    }
    
    BOOL DisplayProcesses(DWORD pid) {
    	// Take a snapshot of all processes in the system.
    	const auto hProcessSnap { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) };
    
    	if (hProcessSnap == INVALID_HANDLE_VALUE) {
    		printError(TEXT("CreateToolhelp32Snapshot (of processes)"));
    		return FALSE;
    	}
    
    	PROCESSENTRY32 pe32 { sizeof(PROCESSENTRY32) };
    
    	// Retrieve information about the first process,
    	// and exit if unsuccessful
    	if (!Process32First(hProcessSnap, &pe32)) {
    		printError(TEXT("Process32First")); // show cause of failure
    		CloseHandle(hProcessSnap);          // clean the snapshot object
    		return FALSE;
    	}
    
    	// Now walk the snapshot of processes, and
    	// display information about each process in turn
    	bool found {};
    
    	do
    		if ((pid == 0) || (pid == pe32.th32ProcessID)) {
    			_tprintf(TEXT("\n  Process name      = %s"), pe32.szExeFile);
    			_tprintf(TEXT("\n  Process ID        = 0x%08X"), pe32.th32ProcessID);
    			_tprintf(TEXT("\n  Thread count      = %d"), pe32.cntThreads);
    			_tprintf(TEXT("\n  Parent process ID = 0x%08X"), pe32.th32ParentProcessID);
    			_tprintf(TEXT("\n  Priority base     = %d"), pe32.pcPriClassBase);
    		}
    	while ((pid == 0 || pid != pe32.th32ProcessID) && (found = Process32Next(hProcessSnap, &pe32)));
    
    	CloseHandle(hProcessSnap);
    	return (pid == 0 || found);
    }
    
    void printError(TCHAR const* msg) {
    	const auto eNum { GetLastError() };
    	TCHAR sysMsg[256];
    
    	FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
    		NULL, eNum,
    		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
    		sysMsg, sizeof(sysMsg), NULL);
    
    	// Trim the end of the line and terminate it with a null
    	auto p { sysMsg };
    
    	while ((*p >= ' ') || (*p == 9))
    		++p;
    
    	do *p-- = 0;
    	while ((p >= sysMsg) && ((*p == '.') || (*p <= ' ')));
    
    	// Display the message
    	_tprintf(TEXT("\n  WARNING: %s failed with error %d (%s)"), msg, eNum, sysMsg);
    }
    Last edited by 2kaud; March 28th, 2025 at 08:23 AM.
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  12. #12
    Join Date
    May 2015
    Posts
    536

    Re: Process info display

    Thankyou so much Kaud !!!. ie great help and highly appreciated. I always got so much support here.

  13. #13
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,903

    Re: Process info display

    I'm not sure what you're really trying to achieve - but do you know about sysinternals? Look at process monitor:
    https://learn.microsoft.com/en-us/sy...nloads/procmon
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  14. #14
    Join Date
    May 2015
    Posts
    536

    Re: Process info display

    Im basically wireless telecom software developer with c, and c++ coming from linux user level programming background (So not a systems programmer ). But wanted to add some logging for the new feature (which adds a process), to the legacy code. So wanted to study about that, before I add the logging.

    Thanks a lot for the inputs, I'll look into the process monitor also

    Btw, I also need to add a timer and wrote about issue in another thread, if you have any comments will be very helpful
    (https://forums.codeguru.com/showthre...multithreading)
    Last edited by pdk5; March 30th, 2025 at 04:48 AM.

  15. #15
    Join Date
    May 2015
    Posts
    536

    Re: Process info display

    Hello,

    Ive finally comeup with the following solution for getting the information related to a process

    1. Memory Usage (I reused existing code in the current code base)
    2. CPU Utilisation (I got some info from the google)
    3. Number of threads (I got this code from Microsoft reference code)

    But the CPU utilisation value is coming bit too big. Not sure if it is related to any issue in the code.
    Ive attached the o/p for reference

    I need to find the number of process spawned by this process. Im thinking I can use the logic in step 3 (to check, if parent process id is same as current process)

    .h
    Code:
    #include <thread>
    #include <chrono>
    #include <functional>
    #include <cstdio>
    #include <atomic>
    
    #include <Pdh.h>
    #include <PdhMsg.h>
    #include <Windows.h>
    
    #include <iostream>
    #include <fstream>
    #include <iomanip> 
    
    #include <processthreadsapi.h>
    #include "psapi.h"
    #include "string.h"
    #include <ctime>
    #include <tlhelp32.h>
    
    using namespace std;
    
    
    class ResourceUtilLoging
    {
    private:
    	ResourceUtilLoging() 
    	{
    		SYSTEM_INFO sysInfo;
    		FILETIME ftime, fsys, fuser;
    
    		GetSystemInfo(&sysInfo);
    		m_nNumProcessors = sysInfo.dwNumberOfProcessors;
    
    		GetSystemTimeAsFileTime(&ftime);
    		memcpy(&m_nLastCpuUsage, &ftime, sizeof(FILETIME));
    
    		m_sProcessHandle = OpenProcess(PROCESS_DUP_HANDLE, FALSE, GetCurrentProcessId());
    		m_sProcessId = GetCurrentProcessId();
    
    		GetProcessTimes(m_sProcessHandle, &ftime, &ftime, &fsys, &fuser);
    		memcpy(&m_nLastCpuUsage, &fsys, sizeof(FILETIME));
    		memcpy(&m_nLastUserCpuUsage, &fuser, sizeof(FILETIME));
    	}
    
    	// TODOPRIYA: If needed, donot stop on destrucor, but on explict call to stop
    	~ResourceUtilLoging() 
    	{
    		CloseHandle( m_sProcessHandle );
    
    		if (m_bRunning) 
    		{
    			stopLog();
    		}
    	}
    
    public:
    
    	static void DisplayLog();
    
    	static double getCurrentCPUValue()
    	{
    		FILETIME ftime, fsys, fuser;
    		ULARGE_INTEGER nNow, nSys, nUser;
    		double percent;
    
    		GetSystemTimeAsFileTime(&ftime);
    		memcpy(&nNow, &ftime, sizeof(FILETIME));
    
    		GetProcessTimes(m_sProcessHandle, &ftime, &ftime, &fsys, &fuser);
    		memcpy(&nSys, &fsys, sizeof(FILETIME));
    		memcpy(&nUser, &fuser, sizeof(FILETIME));
    
    		percent = (nSys.QuadPart - m_nLastSysCpuUsage.QuadPart) +
    			(nUser.QuadPart - m_nLastUserCpuUsage.QuadPart);
    		percent /= (nNow.QuadPart - m_nLastCpuUsage.QuadPart);
    		percent /= m_nNumProcessors;
    		m_nLastCpuUsage = nNow;
    		m_nLastUserCpuUsage = nUser;
    		m_nLastSysCpuUsage = nSys;
    
    		return percent * 100;
    	}
    
    	static BOOL ResourceUtilLoging::DisplayThreads();
    
    	static ResourceUtilLoging& getInstance()
    	{
    		static ResourceUtilLoging theInstance;
    		return theInstance;
    	}
    
    	typedef std::chrono::milliseconds Interval;
    	typedef std::function<void()> Timeout;
    
    	void startLog(const Interval &interval, const Timeout &timeout, string sFileName)
    	{
    
    		m_sLogFileName	=  sFileName;
    
    		m_bRunning		= true;
    
    		m_sThread = std::thread([this, interval, timeout] 
    			{
    			while (m_bRunning) 
    			{
    				std::this_thread::sleep_for(interval);
    
    				timeout();
    			}
    			});
    	}
    	void stopLog() 
    	{
    		m_bRunning = false;
    		m_sThread.join();
    	}
    
    	static std::thread			m_sThread;
    	static std::atomic_bool		m_bRunning;
    
    	static std::string			m_sLogFileName;
    
    	static ULARGE_INTEGER		m_nLastCpuUsage, m_nLastSysCpuUsage, m_nLastUserCpuUsage;
    	static int					m_nNumProcessors;
    	static HANDLE				m_sProcessHandle;
    	static DWORD				m_sProcessId;
    
    	static long long			m_nPhysMemUsedByMePrevious;
    
    };
    
    
    //static PDH_HQUERY cpuQuery;
    //static PDH_HCOUNTER cpuTotal;
    
    //void init()
    //{
    //	PDH_STATUS a = PdhOpenQuery(NULL, NULL, &cpuQuery);
    //	PDH_STATUS i = PdhAddEnglishCounter(cpuQuery, L"\\Processor(_Total)\\% Processor Time", NULL, &cpuTotal);
    //	PdhCollectQueryData(cpuQuery);
    //}
    //
    //double getCurrentValue()
    //{
    //	init();
    //	PDH_FMT_COUNTERVALUE counterVal;
    //
    //	PdhCollectQueryData(cpuQuery);
    //	PdhGetFormattedCounterValue(cpuTotal, PDH_FMT_DOUBLE, NULL, &counterVal);
    //	return counterVal.doubleValue;
    //}
    .cpp
    Code:
    #include "ResourceUtilLoging.h"
    
    
    std::thread				ResourceUtilLoging::m_sThread{};
    std::atomic_bool		ResourceUtilLoging::m_bRunning{};
    
    ULARGE_INTEGER			ResourceUtilLoging::m_nLastCpuUsage{}, ResourceUtilLoging::m_nLastSysCpuUsage{}, ResourceUtilLoging::m_nLastUserCpuUsage{};
    int						ResourceUtilLoging::m_nNumProcessors{};
    HANDLE					ResourceUtilLoging::m_sProcessHandle{};
    DWORD					ResourceUtilLoging::m_sProcessId{};
    
    long long				ResourceUtilLoging::m_nPhysMemUsedByMePrevious;
    
    std::string				ResourceUtilLoging::m_sLogFileName;
    
    void ResourceUtilLoging::DisplayLog()
    {
    	std::ofstream myfile(m_sLogFileName, std::ios::app);
    
    	myfile.setf(std::ios::fixed, std::ios::floatfield);
    	myfile.precision(3);
    
    	time_t now = time(0);
    
    	char dt[ 50 ];
    	std::time_t  t = std::time( NULL );
    	errno_t e = ctime_s( dt, 50, &t );
    	//if (e) std::cout << "err!\n";
    	//else   std::cout << dt;
    
    
    	myfile << endl << string(dt);
    
    	double dCPUUsage = ResourceUtilLoging::getCurrentCPUValue();
    
    	// Now log the CPU Usage for this process
    	if (myfile.is_open())
    	{
    		myfile << "CPU Usgae  : " << dCPUUsage << "\n";
    	}
    
    	long long delta;
    	// Now Log the Memory Usage for this process
    	MEMORYSTATUSEX memInfo;
    	memInfo.dwLength					= sizeof(MEMORYSTATUSEX);
    	GlobalMemoryStatusEx(&memInfo);
    	DWORDLONG totalVirtualMem			= memInfo.ullTotalPageFile;
    	DWORDLONG virtualMemUsed			= memInfo.ullTotalPageFile - memInfo.ullAvailPageFile;
    	DWORDLONG totalPhysMem				= memInfo.ullTotalPhys;
    	DWORDLONG physMemUsed				= memInfo.ullTotalPhys - memInfo.ullAvailPhys;
    
    	PROCESS_MEMORY_COUNTERS_EX pmc;
    	GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc));
    	SIZE_T virtualMemUsedByMe			= pmc.PrivateUsage;
    	SIZE_T physMemUsedByMe				= pmc.WorkingSetSize;
    
    	delta = (long long) physMemUsedByMe - m_nPhysMemUsedByMePrevious;
    
    	myfile << "Process RAM current: " << std::to_string(physMemUsedByMe / 1E9) << " GB, Delta:" << (std::to_string( delta / 1E6)).append(" MB ") << std::endl;
    
    	//message.append(" process RAM current:").append(std::to_string(physMemUsedByMe / 1E9)).append(" GB");
    	m_nPhysMemUsedByMePrevious = (long long) physMemUsedByMe;
    
    
    	// Display the Thread count of the current process
    	DisplayThreads();
    }
    
    BOOL ResourceUtilLoging::DisplayThreads() 
    {
    
    	std::ofstream myfile(m_sLogFileName, std::ios::app);
    
    	myfile.setf(std::ios::fixed, std::ios::floatfield);
    	myfile.precision(3);
    
    	time_t now = time(0);
    
    	// Take a snapshot of all processes in the system.
    	const auto hProcessSnap { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) };
    
    	if (hProcessSnap == INVALID_HANDLE_VALUE) {
    		//printError(TEXT("CreateToolhelp32Snapshot (of processes)"));
    		return FALSE;
    	}
    
    	PROCESSENTRY32 pe32 { sizeof(PROCESSENTRY32) };
    
    	// Retrieve information about the first process,
    	// and exit if unsuccessful
    	if (!Process32First(hProcessSnap, &pe32)) {
    		//printError(TEXT("Process32First")); // show cause of failure
    		CloseHandle(hProcessSnap);          // clean the snapshot object
    		return FALSE;
    	}
    
    	// Now walk the snapshot of processes, and
    	// display information about each process in turn
    	bool found {};
    
    	do
    		if ((m_sProcessId == 0) || (m_sProcessId == pe32.th32ProcessID))
    		{
    			//_tprintf(TEXT("\n  Process name      = %s"), pe32.szExeFile);
    			//_tprintf(TEXT("\n  Process ID        = 0x%08X"), pe32.th32ProcessID);
    			//_tprintf(TEXT("\n  Thread count      = %d"), pe32.cntThreads);
    			//_tprintf(TEXT("\n  Parent process ID = 0x%08X"), pe32.th32ParentProcessID);
    			//_tprintf(TEXT("\n  Priority base     = %d"), pe32.pcPriClassBase);
    
    			myfile << "Process Thread Current:  : " << std::to_string(pe32.cntThreads) << endl;
    		}
    	while ((m_sProcessId == 0 || m_sProcessId != pe32.th32ProcessID) && (found = Process32Next(hProcessSnap, &pe32)));
    
    	CloseHandle(hProcessSnap);
    	return (m_sProcessId == 0 || found);
    }

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured