Chromium Code Reviews| 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 thread names in a process specified. | |
| 19 BOOL ListProcessThreadNames(DWORD dwOwnerPID); | |
| 20 // Print the error message. | |
| 21 void printError(TCHAR* msg); | |
| 22 | |
| 23 // The GetThreadDescription API is available since Windows 10, version 1607. | |
| 24 // The reason why this API is binded in this way rather than just using the | |
|
brucedawson
2017/02/23 19:33:11
binded -> bound
chengx
2017/02/23 20:45:06
Done.
| |
| 25 // Windows SDK, is to make it consistent with the bind of SetThreadDescription | |
| 26 // in Chrome. Binding SetThreadDescription API in Chrome can only be done via | |
| 27 // the system dll, rather than SDK. | |
|
brucedawson
2017/02/23 19:33:12
"can only be done by GetProcAddress, rather than t
chengx
2017/02/23 20:45:06
Done.
| |
| 28 typedef HRESULT(WINAPI* GETTHREADDESCRIPTION)(HANDLE hThread, | |
| 29 PWSTR* threadDescription); | |
| 30 | |
| 31 int main(void) { | |
| 32 unsigned int processId; | |
|
brucedawson
2017/02/23 19:33:11
Should use DWORD as type for consistency.
chengx
2017/02/23 20:45:06
Done.
| |
| 33 std::string user_input; | |
| 34 while (true) { | |
| 35 std::cout | |
| 36 << "\nPlease enter the process Id, or \"quit\" to end the program : "; | |
| 37 std::getline(std::cin, user_input); | |
| 38 if (user_input == "quit") | |
| 39 break; | |
| 40 std::cout << std::endl; | |
| 41 std::stringstream ss(user_input); | |
| 42 if (ss >> processId) { | |
| 43 ListProcessThreadNames(processId); | |
| 44 } else { | |
| 45 std::cout << "input is invalid" << std::endl; | |
| 46 } | |
| 47 std::cout << std::endl; | |
| 48 } | |
| 49 return 0; | |
| 50 } | |
| 51 | |
| 52 BOOL ListProcessThreadNames(DWORD dwOwnerPID) { | |
| 53 auto get_thread_description_func = | |
| 54 reinterpret_cast<GETTHREADDESCRIPTION>(::GetProcAddress( | |
| 55 ::GetModuleHandle(L"Kernel32.dll"), "GetThreadDescription")); | |
| 56 | |
| 57 if (!get_thread_description_func) { | |
| 58 printError(TEXT("GetThreadDescription")); | |
| 59 return (FALSE); | |
| 60 } | |
| 61 | |
| 62 HANDLE threadSnap = INVALID_HANDLE_VALUE; | |
| 63 // Take a snapshot of all running threads. | |
| 64 threadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); | |
| 65 if (threadSnap == INVALID_HANDLE_VALUE) { | |
| 66 printError(TEXT("CreateToolhelp32Snapshot")); | |
| 67 return (FALSE); | |
| 68 } | |
| 69 | |
| 70 THREADENTRY32 te32; | |
| 71 te32.dwSize = sizeof(THREADENTRY32); | |
| 72 | |
| 73 // Retrieve information about the first thread, and exit if unsuccessful. | |
| 74 if (!Thread32First(threadSnap, &te32)) { | |
| 75 printError(TEXT("Thread32First")); | |
| 76 CloseHandle(threadSnap); | |
| 77 return (FALSE); | |
| 78 } | |
| 79 | |
| 80 // Walk the thread list of the system, and display ID and name about each | |
| 81 // thread associated with the process specified. | |
| 82 std::cout << "thread_ID thread_name" << std::endl; | |
| 83 std::multimap<std::wstring, DWORD> name_id_map; | |
| 84 do { | |
| 85 if (te32.th32OwnerProcessID == dwOwnerPID) { | |
| 86 HANDLE threadHandle = | |
| 87 OpenThread(THREAD_QUERY_INFORMATION, FALSE, te32.th32ThreadID); | |
| 88 if (threadHandle) { | |
| 89 PWSTR data; | |
| 90 HRESULT hr = get_thread_description_func(threadHandle, &data); | |
| 91 if (SUCCEEDED(hr)) { | |
| 92 std::wstring data_w(data); | |
| 93 name_id_map.insert(std::make_pair(data_w, te32.th32ThreadID)); | |
|
brucedawson
2017/02/23 19:33:11
Don't forget to free the text with LocalFree, per
chengx
2017/02/23 20:45:06
Done.
| |
| 94 } else { | |
| 95 printError(TEXT("GetThreadDescription")); | |
| 96 } | |
| 97 CloseHandle(threadHandle); | |
| 98 } else { | |
| 99 printError(TEXT("OpenThread")); | |
| 100 } | |
| 101 } | |
| 102 } while (Thread32Next(threadSnap, &te32)); | |
| 103 | |
| 104 // Clean up the snapshot object. | |
| 105 CloseHandle(threadSnap); | |
| 106 | |
| 107 // Show all thread ID/name pairs. | |
| 108 for (auto it = name_id_map.begin(); it != name_id_map.end(); ++it) { | |
| 109 std::cout << it->second << "\t"; | |
| 110 std::wcout << it->first << std::endl; | |
| 111 } | |
| 112 | |
| 113 return (TRUE); | |
| 114 } | |
| 115 | |
| 116 void printError(TCHAR* msg) { | |
| 117 DWORD eNum; | |
| 118 TCHAR sysMsg[256]; | |
| 119 TCHAR* p; | |
| 120 | |
| 121 eNum = GetLastError(); | |
| 122 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, | |
| 123 NULL, eNum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), sysMsg, | |
| 124 256, NULL); | |
| 125 | |
| 126 // Trim the end of the line and terminate it with a null. | |
| 127 p = sysMsg; | |
| 128 while ((*p > 31) || (*p == 9)) | |
| 129 ++p; | |
| 130 do { | |
| 131 *p-- = 0; | |
| 132 } while ((p >= sysMsg) && ((*p == '.') || (*p < 33))); | |
| 133 | |
| 134 // Display the message. | |
| 135 _tprintf(TEXT("\n WARNING: %s failed with error %d (%s)"), msg, eNum, | |
| 136 sysMsg); | |
| 137 } | |
|
brucedawson
2017/02/23 19:37:32
Put a line terminator on the last line.
chengx
2017/02/23 20:45:06
Done.
| |
| OLD | NEW |