On 22 Nov 2022 21:16, Bonita Montero wrote:
> I developed a little program which lists the process tree of Windows.
>
> [snip code]
>
> The process tree is built inside a single vector and printed with a
> recursive lambda.
There is one thing I wonder about, namely the use of the type of a
non-capturing lambda as the type of a unique_ptr deleter. Does the
standard guarantee that such type is default-constructible?
Anyway, when I ran your program it displayed a lot of apparently top
level processes, but I found that many processes have an ultimate top
level ancestor process that no longer exists.
So to get a view of all groups (e.g. Google stuff in a group because
started by a common no longer existing process), I used code like this:
#include <windows-api-header-wrappers/windows-h.for-utf-16.hpp>
#include <tlhelp32.h>
#include <fmt/core.h>
#include <fmt/xchar.h> // wchar_t support
#include <map>
#include <stack>
#include <stdexcept>
#include <string>
#include <string_view>
#include <vector>
#include <stdlib.h>
#define FAIL( message ) \
support_machinery::fail( std::string() + __func__ + " - " + (message) )
namespace support_machinery {
using std::stack, // <stack>
std::runtime_error, // <stdexcept>
std::string; // <string>
template< class T > using in_ = const T&;
auto hopefully( const bool condition ) -> bool { return condition; }
auto fail( in_<string> s ) -> bool { throw runtime_error( s ); }
template< class Container >
auto is_empty( in_<Container> c ) -> bool { return c.empty(); }
template< class Item >
auto popped_top_of( stack<Item>& st )
-> Item
{
Item result = st.top();
st.pop();
return result;
}
} // namespace support_machinery
namespace process {
namespace sm = support_machinery;
using std::map, // <map>
std::wstring, // <string>
std::vector; // <vector>
struct Snapshot
{
const HANDLE handle;
struct Entry: PROCESSENTRY32
{
Entry() { dwSize = sizeof( PROCESSENTRY32 ); }
};
~Snapshot() { ::CloseHandle( handle ); }
Snapshot():
handle( ::CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 ) )
{
sm::hopefully( handle != INVALID_HANDLE_VALUE )
or FAIL( "::CreateToolhelp32Snapshot failed" );
}
};
using Id = DWORD;
constexpr auto unknown_id = Id( -1 );
struct Info
{
Id id;
Id parent_id;
vector<Id> child_ids;
wstring exe_name;
};
struct Tree: public map<Id, Info>
{
Tree()
{
auto& self = *this;
auto ss = process::Snapshot();
auto entry = process::Snapshot::Entry();
::Process32First( ss.handle, &entry )
or FAIL( "::Process32First failed to retrieve the first
process entry." );
do {
const auto id = entry.th32ProcessID;
const auto parent_id = entry.th32ParentProcessID;
const auto it = self.find( id );
if( it == self.end() ) {
self.emplace( id, process::Info{ id, parent_id, {},
entry.szExeFile } );
} else {
auto& info = it->second;
info.parent_id = parent_id;
info.exe_name = entry.szExeFile;
}
if( id != 0 ) {
const auto it_parent = self.find( parent_id );
if( it_parent == self.end() ) {
self.emplace( parent_id, process::Info{
parent_id, unknown_id, {id}, L"?" } );
} else {
auto& parent_info = it_parent->second;
parent_info.child_ids.push_back( id );
}
}
} while( ::Process32Next( ss.handle, &entry ) );
sm::hopefully( ::GetLastError() == ERROR_NO_MORE_FILES )
or FAIL( "Failed to enumerate processes." );
}
};
} // namespace process
namespace app {
namespace sm = support_machinery;
using sm::in_, sm::is_empty, sm::popped_top_of;
using std::stack, // <stack>
std::wstring, // <string>
std::wstring_view; // <string_view>
auto output( in_<wstring_view> s )
{
// Writing directly to console because fmt::print fouls up wide
non-ASCII.
static const HANDLE out = GetStdHandle( STD_OUTPUT_HANDLE );
WriteConsole( out, s.data(), DWORD( s.size() ), nullptr, nullptr );
}
auto indent_string( const int n )
-> wstring
{
static const auto unit = L"." + wstring( 3, L' ' );
wstring result;
for( int i = 1; i <= n; ++i ) { result += unit; }
return result;
}
void display( const process::Id id, const int level, in_<wstring>
name )
{
const wstring quoted_name = (name.front() == L'?'? L"???" :
fmt::format( L"“{}”", name ));
const wstring indent = indent_string( level );
output( fmt::format( L"{:8d}{:2}{}{:s}\n", id, L"", indent,
quoted_name ) );
}
void display_with_root( const process::Id root_id, const
process::Tree& tree )
{
struct Node{ process::Id process_id; int level; };
auto remaining = stack<Node>();
remaining.push( {root_id, 0} );
while( not is_empty( remaining ) ) {
const Node node = popped_top_of(
remaining );
const process::Info& info =
tree.at(
node.process_id );
display( node.process_id, node.level, info.exe_name );
for( const process::Id child_id: info.child_ids ) {
remaining.push( Node{ child_id, node.level + 1 } );
}
}
}
void run()
{
const auto tree = process::Tree();
for( const auto& [id, info]: tree ) {
if( id == 0 or info.parent_id == process::unknown_id ) {
display_with_root( id, tree );
}
}
}
} // namespace app
auto main() -> int
{
using std::exception;
using support_machinery::in_;
try {
app::run();
return EXIT_SUCCESS;
} catch( in_<exception> x ) {
fmt::print( "!{}\n", x.what() );
}
return EXIT_FAILURE;
}
Typical result:
0 “[System Process]”
4 . “System”
2960 . . “Memory Compression”
684 . . “smss.exe”
176 . . “Registry”
808 ???
748 . “wininit.exe”
1300 . . “fontdrvhost.exe”
1128 . . “lsass.exe”
1076 . . “services.exe”
20520 . . . “svchost.exe”
43056 . . . “svchost.exe”
30436 . . . “svchost.exe”
36384 . . . “NisSrv.exe”
5540 . . . “svchost.exe”
17952 . . . “svchost.exe”
16808 . . . “svchost.exe”
2520 . . . “svchost.exe”
8488 . . . “svchost.exe”
11972 . . . “svchost.exe”
7408 . . . “svchost.exe”
10308 . . . “svchost.exe”
7916 . . . “svchost.exe”
11176 . . . “SgrmBroker.exe”
10900 . . . “svchost.exe”
6196 . . . “svchost.exe”
4424 . . . “svchost.exe”
1920 . . . “svchost.exe”
10876 . . . “svchost.exe”
10780 . . . “svchost.exe”
10296 . . . “SecurityHealthService.exe”
9388 . . . “svchost.exe”
9152 . . . “SearchIndexer.exe”
8740 . . . “svchost.exe”
8584 . . . “svchost.exe”
7996 . . . “svchost.exe”
7584 . . . “svchost.exe”
7524 . . . “svchost.exe”
7468 . . . “svchost.exe”
7456 . . . “svchost.exe”
7256 . . . “svchost.exe”
4356 . . . “svchost.exe”
6576 . . . “svchost.exe”
6736 . . . “svchost.exe”
42056 . . . . “MoUsoCoreWorker.exe”
6032 . . . “svchost.exe”
4036 . . . “svchost.exe”
5840 . . . “svchost.exe”
4892 . . . “svchost.exe”
4716 . . . “jhi_service.exe”
4536 . . . “Intel_PIE_Service.exe”
4516 . . . “MBAMService.exe”
7232 . . . . “mbamtray.exe”
4504 . . . “svchost.exe”
4396 . . . “LMS.exe”
4308 . . . “WMIRegistrationService.exe”
4288 . . . “RstMwService.exe”
4260 . . . “OfficeClickToRun.exe”
4252 . . . “MsMpEng.exe”
4244 . . . “RtkAudUService64.exe”
4220 . . . “svchost.exe”
4212 . . . “svchost.exe”
4196 . . . “Lenovo.Modern.ImController.exe”
27020 . . . .
“Lenovo.Modern.ImController.PluginHost.Device.exe”
4188 . . . “svchost.exe”
4180 . . . “svchost.exe”
4172 . . . “svchost.exe”
4164 . . . “LenovoVantageService.exe”
3416 . . . . “LenovoVantage-(LenovoCompanionAppAddin).exe”
780 . . . . “LenovoVantage-(LenovoBoostSystemAddin).exe”
3496 . . . . “LenovoVantage-(LenovoBoostAddin).exe”
11184 . . . . “LenovoVantage-(LenovoServiceBridgeAddin).exe”
11852 . . . . “LenovoVantage-(VantageCoreAddin).exe”
4156 . . . “svchost.exe”
4148 . . . “OneApp.IGCC.WinService.exe”
4140 . . . “svchost.exe”
5472 . . . . “AggregatorHost.exe”
3912 . . . “svchost.exe”
3860 . . . “svchost.exe”
3800 . . . “spoolsv.exe”
3744 . . . “svchost.exe”
3712 . . . “svchost.exe”
4016 . . . . “wlanext.exe”
4024 . . . . . “conhost.exe”
3632 . . . “svchost.exe”
3436 . . . “svchost.exe”
3428 . . . “svchost.exe”
3420 . . . “svchost.exe”
3260 . . . “svchost.exe”
10136 . . . . “ctfmon.exe”
3232 . . . “svchost.exe”
3112 . . . “WUDFHost.exe”
1604 . . . “svchost.exe”
2888 . . . “svchost.exe”
2880 . . . “svchost.exe”
2808 . . . “svchost.exe”
2800 . . . “svchost.exe”
2776 . . . “svchost.exe”
2768 . . . “svchost.exe”
2728 . . . “svchost.exe”
2600 . . . “svchost.exe”
2592 . . . “svchost.exe”
2456 . . . “igfxCUIService.exe”
7504 . . . . “igfxEM.exe”
2296 . . . “svchost.exe”
2280 . . . “IntelCpHeciSvc.exe”
2244 . . . “svchost.exe”
2068 . . . “svchost.exe”
1516 . . . “svchost.exe”
1276 . . . “svchost.exe”
1168 . . . “svchost.exe”
716 . . . “svchost.exe”
7396 . . . . “sihost.exe”
10588 . . . . . “IGCCTray.exe”
1036 . . . . “winlogon.exe”
1624 . . . . . “dwm.exe”
1296 . . . . . “fontdrvhost.exe”
704 . . . . “csrss.exe”
2028 . . . “IntelCpHDCPSvc.exe”
1884 . . . “svchost.exe”
1872 . . . “svchost.exe”
1860 . . . “svchost.exe”
1844 . . . “svchost.exe”
7684 . . . . “taskhostw.exe”
2532 . . . . “helperservice.exe”
3224 . . . . . “conhost.exe”
1732 . . . “svchost.exe”
1724 . . . “svchost.exe”
1716 . . . “svchost.exe”
1492 . . . “svchost.exe”
1452 . . . “svchost.exe”
1368 . . . “WUDFHost.exe”
1344 . . . “svchost.exe”
1264 . . . “svchost.exe”
32548 . . . . “RuntimeBroker.exe”
41928 . . . . “LockApp.exe”
31396 . . . . “backgroundTaskHost.exe”
26204 . . . . “backgroundTaskHost.exe”
36372 . . . . “FESearchHost.exe”
40420 . . . . “backgroundTaskHost.exe”
34948 . . . . “explorer.exe”
30600 . . . . “backgroundTaskHost.exe”
21008 . . . . “backgroundTaskHost.exe”
19548 . . . . “RuntimeBroker.exe”
17424 . . . . “explorer.exe”
15712 . . . . “explorer.exe”
15876 . . . . . “vlc.exe”
19184 . . . . “UserOOBEBroker.exe”
19004 . . . . “SystemSettings.exe”
19392 . . . . “SystemSettingsBroker.exe”
19112 . . . . “RuntimeBroker.exe”
14380 . . . . “ShellExperienceHost.exe”
4440 . . . . “backgroundTaskHost.exe”
12392 . . . . “backgroundTaskHost.exe”
10604 . . . . “RuntimeBroker.exe”
12440 . . . . “CalculatorApp.exe”
3832 . . . . “dllhost.exe”
8444 . . . . “RuntimeBroker.exe”
10416 . . . . “Video.UI.exe”
4132 . . . . “ApplicationFrameHost.exe”
2840 . . . . “RuntimeBroker.exe”
9076 . . . . “IGCC.exe”
11084 . . . . “explorer.exe”
11120 . . . . . “SumatraPDF.exe”
14148 . . . . . “ClocX.exe”
4008 . . . . . “Notepad.exe”
10440 . . . . . “WinSnap.exe”
8344 . . . . . “notepad++.exe”
9536 . . . . “TextInputHost.exe”
5696 . . . . “RuntimeBroker.exe”
8976 . . . . “PhoneExperienceHost.exe”
9648 . . . . “dllhost.exe”
9248 . . . . “RuntimeBroker.exe”
1236 . . . . “RuntimeBroker.exe”
8620 . . . . “Widgets.exe”
7840 . . . . “StartMenuExperienceHost.exe”
7832 . . . . “SearchHost.exe”
956 . “csrss.exe”
2080 ???
3672 . “cmd.exe”
1468 . . “LSB.exe”
2680 . . “conhost.exe”
7380 ???
7792 . “explorer.exe”
30724 . . “foobar2000.exe”
9840 . . “Taskmgr.exe”
11984 . . “chrome.exe”
40128 . . . “chrome.exe”
33304 . . . “chrome.exe”
33716 . . . “chrome.exe”
27036 . . . “chrome.exe”
40008 . . . “chrome.exe”
13780 . . . “chrome.exe”
17792 . . . “chrome.exe”
6564 . . . “chrome.exe”
18400 . . . “chrome.exe”
18028 . . . “chrome.exe”
16628 . . . “chrome.exe”
17680 . . . “chrome.exe”
1052 . . “ONENOTEM.EXE”
10932 . . “ROTELAudioCplApp.exe”
10488 . . “fdm.exe”
10352 . . “RtkAudUService64.exe”
10276 . . “SecurityHealthSystray.exe”
7756 ???
8848 . “GoogleCrashHandler64.exe”
8836 . “GoogleCrashHandler.exe”
21096 ???
21172 . “WindowsTerminal.exe”
328 . . “cmd.exe”
27888 . . . “b.exe”
9444 . . “OpenConsole.exe”
42024 ???
41224 . “vctip.exe”
- Alf