Index: tools/win/ShowThreadNames/ShowThreadNames.cc |
diff --git a/tools/win/ShowThreadNames/ShowThreadNames.cc b/tools/win/ShowThreadNames/ShowThreadNames.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..004e615d22bd14b6664b57b5a5bcbbbfc600d26e |
--- /dev/null |
+++ b/tools/win/ShowThreadNames/ShowThreadNames.cc |
@@ -0,0 +1,126 @@ |
+// 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 threads in a process specified. |
+BOOL ListProcessThreadNames(DWORD dwOwnerPID); |
+ |
+// 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.
|
+typedef HRESULT(WINAPI* GETTHREADDESCRIPTION)(HANDLE hThread, |
+ PWSTR* threadDescription); |
+ |
+template <typename A, typename B> |
+std::pair<B, A> flip_pair(const std::pair<A, B>& p) { |
+ return std::pair<B, A>(p.second, p.first); |
+} |
+ |
+template <typename A, typename B> |
+std::multimap<B, A> flip_map(const std::map<A, B>& src) { |
+ std::multimap<B, A> dst; |
+ std::transform(src.begin(), src.end(), std::inserter(dst, dst.begin()), |
+ flip_pair<A, B>); |
+ return dst; |
+} |
+ |
+int main(void) { |
+ unsigned int processId; |
+ 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); |
+ std::cout << std::endl; |
+ if (user_input == "quit") |
+ break; |
+ std::stringstream ss(user_input); |
+ if (ss >> processId) { |
+ ListProcessThreadNames(processId); |
+ } else { |
+ std::cout << "input is invalid" << std::endl; |
+ } |
+ std::cout << std::endl; |
+ } |
+ return 0; |
+} |
+ |
+BOOL ListProcessThreadNames(DWORD dwOwnerPID) { |
+ HMODULE kernel32dll = ::GetModuleHandle(L"Kernel32.dll"); |
+ |
+ 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.
|
+ std::cout << "Error: cannot find Kernel32.dll" << std::endl; |
+ return (FALSE); |
+ } |
+ |
+ auto get_thread_description_func = reinterpret_cast<GETTHREADDESCRIPTION>( |
+ ::GetProcAddress(kernel32dll, "GetThreadDescription")); |
+ |
+ if (!get_thread_description_func) { |
+ std::cout << "GetThreadDescription API is not available in current OS" |
+ << std::endl; |
+ return (FALSE); |
+ } |
+ |
+ 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.
|
+ // Take a snapshot of all running threads |
+ hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); |
+ if (hThreadSnap == INVALID_HANDLE_VALUE) |
+ return (FALSE); |
+ |
+ THREADENTRY32 te32; |
+ te32.dwSize = sizeof(THREADENTRY32); |
+ |
+ // Retrieve information about the first thread, and exit if unsuccessful |
+ if (!Thread32First(hThreadSnap, &te32)) { |
+ std::cout << "Thread32First() call failed" << std::endl; |
+ CloseHandle(hThreadSnap); |
+ 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::map<DWORD, std::wstring> id_name_map; |
+ do { |
+ if (te32.th32OwnerProcessID == dwOwnerPID) { |
+ HANDLE threadHandle = |
+ 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.
|
+ if (threadHandle) { |
+ PWSTR data; |
+ HRESULT hr = get_thread_description_func(threadHandle, &data); |
+ if (SUCCEEDED(hr)) { |
+ std::wstring data_w(data); |
+ id_name_map[te32.th32ThreadID] = data_w; |
+ } else { |
+ std::cout << "GetThreadDescription API call failed" << std::endl; |
+ } |
+ CloseHandle(threadHandle); |
+ } |
+ } |
+ } while (Thread32Next(hThreadSnap, &te32)); |
+ |
+ // 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.
|
+ 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.
|
+ |
+ // show thread ID and name. |
+ for (auto it = name_id_map.begin(); it != name_id_map.end(); ++it) { |
+ std::cout << it->second << "\t"; |
+ std::wcout << it->first << std::endl; |
+ } |
+ |
+ // clean up the snapshot object. |
+ 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.
|
+ return (TRUE); |
+} |