1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
// Copyright (c) 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <tlhelp32.h>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <map>
#include <sstream>
#include <string>
// List all thread names in a process specified.
BOOL ListProcessThreadNames(DWORD owner_pid);
// Print the error message.
void printError(TCHAR* msg);
// The GetThreadDescription API is available since Windows 10, version 1607.
// The reason why this API is bound in this way rather than just using the
// Windows SDK, is that this API isn't yet available in the SDK that Chrome
// builds with.
// Binding SetThreadDescription API in Chrome can only be done by
// GetProcAddress, rather than the import library.
typedef HRESULT(WINAPI* GETTHREADDESCRIPTION)(HANDLE hThread,
PWSTR* threadDescription);
int main(void) {
DWORD process_Id;
std::string user_input;
while (true) {
std::cout
<< "\nPlease enter the process Id, or \"quit\" to end the program : ";
std::getline(std::cin, user_input);
// Convert the user input to lower case.
std::transform(user_input.begin(), user_input.end(), user_input.begin(),
::tolower);
if (user_input == "quit")
break;
std::cout << std::endl;
std::stringstream ss(user_input);
if (ss >> process_Id) {
ListProcessThreadNames(process_Id);
} else {
std::cout << "Input is invalid" << std::endl;
}
std::cout << std::endl;
}
return 0;
}
BOOL ListProcessThreadNames(DWORD owner_pid) {
auto get_thread_description_func =
reinterpret_cast<GETTHREADDESCRIPTION>(::GetProcAddress(
::GetModuleHandle(L"Kernel32.dll"), "GetThreadDescription"));
if (!get_thread_description_func) {
printError(TEXT("GetThreadDescription"));
return (FALSE);
}
HANDLE thread_snapshot = INVALID_HANDLE_VALUE;
// Take a snapshot of all running threads.
thread_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
if (thread_snapshot == INVALID_HANDLE_VALUE) {
printError(TEXT("CreateToolhelp32Snapshot"));
return (FALSE);
}
THREADENTRY32 te32;
te32.dwSize = sizeof(THREADENTRY32);
// Retrieve information about the first thread, and exit if unsuccessful.
if (!Thread32First(thread_snapshot, &te32)) {
printError(TEXT("Thread32First"));
CloseHandle(thread_snapshot);
return (FALSE);
}
// Walk the thread list of the system, and display ID and name about each
// thread associated with the process specified.
std::cout << "thread_ID thread_name" << std::endl;
std::multimap<std::wstring, DWORD> name_id_map;
do {
if (te32.th32OwnerProcessID == owner_pid) {
HANDLE thread_handle =
OpenThread(THREAD_QUERY_INFORMATION, FALSE, te32.th32ThreadID);
if (thread_handle) {
PWSTR data;
HRESULT hr = get_thread_description_func(thread_handle, &data);
if (SUCCEEDED(hr)) {
std::wstring thread_name(data);
LocalFree(data);
name_id_map.insert(std::make_pair(thread_name, te32.th32ThreadID));
} else {
printError(TEXT("GetThreadDescription"));
}
CloseHandle(thread_handle);
} else {
printError(TEXT("OpenThread"));
}
}
} while (Thread32Next(thread_snapshot, &te32));
// Clean up the snapshot object.
CloseHandle(thread_snapshot);
// Show all thread ID/name pairs.
for (auto name_id_pair : name_id_map) {
std::cout << name_id_pair.second << "\t";
std::wcout << name_id_pair.first << std::endl;
}
return (TRUE);
}
void printError(TCHAR* 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), 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);
}
|