OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2017 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include <windows.h> | |
6 | |
7 #include <stdio.h> | |
8 #include <tchar.h> | |
9 #include <tlhelp32.h> | |
10 | |
11 #include <algorithm> | |
12 #include <iostream> | |
13 #include <iterator> | |
14 #include <map> | |
15 #include <sstream> | |
16 #include <string> | |
17 | |
18 // List all threads in a process specified. | |
19 BOOL ListProcessThreadNames(DWORD dwOwnerPID); | |
20 | |
21 // The GetThreadDescription API is available since Windows 10, version 1607. | |
stanisc
2017/02/23 02:29:59
Perhaps you should mention why you have to bind to
chengx
2017/02/23 03:26:04
Done.
| |
22 typedef HRESULT(WINAPI* GETTHREADDESCRIPTION)(HANDLE hThread, | |
23 PWSTR* threadDescription); | |
24 | |
25 template <typename A, typename B> | |
26 std::pair<B, A> flip_pair(const std::pair<A, B>& p) { | |
27 return std::pair<B, A>(p.second, p.first); | |
28 } | |
29 | |
30 template <typename A, typename B> | |
31 std::multimap<B, A> flip_map(const std::map<A, B>& src) { | |
32 std::multimap<B, A> dst; | |
33 std::transform(src.begin(), src.end(), std::inserter(dst, dst.begin()), | |
34 flip_pair<A, B>); | |
35 return dst; | |
36 } | |
37 | |
38 int main(void) { | |
39 unsigned int processId; | |
40 std::string user_input; | |
41 while (true) { | |
42 std::cout | |
43 << "\nPlease enter the process Id, or \"quit\" to end the program : "; | |
44 std::getline(std::cin, user_input); | |
45 std::cout << std::endl; | |
46 if (user_input == "quit") | |
47 break; | |
48 std::stringstream ss(user_input); | |
49 if (ss >> processId) { | |
50 ListProcessThreadNames(processId); | |
51 } else { | |
52 std::cout << "input is invalid" << std::endl; | |
53 } | |
54 std::cout << std::endl; | |
55 } | |
56 return 0; | |
57 } | |
58 | |
59 BOOL ListProcessThreadNames(DWORD dwOwnerPID) { | |
60 HMODULE kernel32dll = ::GetModuleHandle(L"Kernel32.dll"); | |
61 | |
62 if (!kernel32dll) { | |
brucedawson
2017/02/23 01:57:26
I'd skip this error checking 'cause kernel32.dll w
chengx
2017/02/23 03:26:04
Done.
| |
63 std::cout << "Error: cannot find Kernel32.dll" << std::endl; | |
64 return (FALSE); | |
65 } | |
66 | |
67 auto get_thread_description_func = reinterpret_cast<GETTHREADDESCRIPTION>( | |
68 ::GetProcAddress(kernel32dll, "GetThreadDescription")); | |
69 | |
70 if (!get_thread_description_func) { | |
71 std::cout << "GetThreadDescription API is not available in current OS" | |
72 << std::endl; | |
73 return (FALSE); | |
74 } | |
75 | |
76 HANDLE hThreadSnap = INVALID_HANDLE_VALUE; | |
stanisc
2017/02/23 02:29:59
I'd suggest to not use Hungarian notation i.e. han
chengx
2017/02/23 03:26:03
Changed to threadSnap.
| |
77 // Take a snapshot of all running threads | |
78 hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); | |
79 if (hThreadSnap == INVALID_HANDLE_VALUE) | |
80 return (FALSE); | |
81 | |
82 THREADENTRY32 te32; | |
83 te32.dwSize = sizeof(THREADENTRY32); | |
84 | |
85 // Retrieve information about the first thread, and exit if unsuccessful | |
86 if (!Thread32First(hThreadSnap, &te32)) { | |
87 std::cout << "Thread32First() call failed" << std::endl; | |
88 CloseHandle(hThreadSnap); | |
89 return (FALSE); | |
90 } | |
91 | |
92 // Walk the thread list of the system, and display ID and name about each | |
93 // thread associated with the process specified. | |
94 std::cout << "thread_ID thread_name" << std::endl; | |
95 std::map<DWORD, std::wstring> id_name_map; | |
96 do { | |
97 if (te32.th32OwnerProcessID == dwOwnerPID) { | |
98 HANDLE threadHandle = | |
99 OpenThread(THREAD_ALL_ACCESS, FALSE, te32.th32ThreadID); | |
brucedawson
2017/02/23 01:57:26
You can probably use THREAD_QUERY_LIMITED_INFORMAT
chengx
2017/02/23 03:26:03
Done.
| |
100 if (threadHandle) { | |
101 PWSTR data; | |
102 HRESULT hr = get_thread_description_func(threadHandle, &data); | |
103 if (SUCCEEDED(hr)) { | |
104 std::wstring data_w(data); | |
105 id_name_map[te32.th32ThreadID] = data_w; | |
106 } else { | |
107 std::cout << "GetThreadDescription API call failed" << std::endl; | |
108 } | |
109 CloseHandle(threadHandle); | |
110 } | |
111 } | |
112 } while (Thread32Next(hThreadSnap, &te32)); | |
113 | |
114 // reverse the map so now it is sorted by thread name. | |
stanisc
2017/02/23 02:29:59
Nit: comments are supposed to be complete sentence
chengx
2017/02/23 03:26:04
Done.
| |
115 std::multimap<std::wstring, DWORD> name_id_map = flip_map(id_name_map); | |
brucedawson
2017/02/23 01:57:26
If you're going to put it in a multimap<wstring,DW
chengx
2017/02/23 03:26:03
I will use multimap<wstring,DWORD> directly.
| |
116 | |
117 // show thread ID and name. | |
118 for (auto it = name_id_map.begin(); it != name_id_map.end(); ++it) { | |
119 std::cout << it->second << "\t"; | |
120 std::wcout << it->first << std::endl; | |
121 } | |
122 | |
123 // clean up the snapshot object. | |
124 CloseHandle(hThreadSnap); | |
brucedawson
2017/02/23 01:57:26
For tidiness consider closing the handle as soon a
chengx
2017/02/23 03:26:04
Done.
| |
125 return (TRUE); | |
126 } | |
OLD | NEW |