-
Notifications
You must be signed in to change notification settings - Fork 271
Add Toolhelp32Snapshot helpers #438
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
HO-COOH
wants to merge
9
commits into
microsoft:master
Choose a base branch
from
HO-COOH:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
009095d
Create stub for toolhelp32
HO-COOH 785d711
Finish implementation
HO-COOH c982bbe
Create stub for toolhelp32
HO-COOH 6ccd95b
Finish implementation
HO-COOH 76eb9f8
Remove from common_source
HO-COOH a9891ad
Merge branch 'master' of https://github.com/HO-COOH/wil
HO-COOH b946d29
Remove Toolhelp32Test from COMMON_SOURCES
HO-COOH 091494e
Fix: Suggested fixes from PR #438
HO-COOH b78d3c8
Fix test not formated
HO-COOH File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -334,3 +334,4 @@ ASALocalRun/ | |
|
|
||
| # CMake/Build output | ||
| build/ | ||
| /CMakeSettings.json | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,337 @@ | ||
| //********************************************************* | ||
| // | ||
| // Copyright (c) Microsoft. All rights reserved. | ||
| // This code is licensed under the MIT License. | ||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | ||
| // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | ||
| // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | ||
| // PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
| // | ||
| //********************************************************* | ||
| #ifndef __WIL_TOOLHELP32_INCLUDED | ||
| #define __WIL_TOOLHELP32_INCLUDED | ||
| #include <TlHelp32.h> | ||
| #include <processthreadsapi.h> | ||
| #include "resource.h" | ||
| namespace wil | ||
| { | ||
| namespace details | ||
| { | ||
| template <typename TEntry, typename TEnumApi, typename TCallback> | ||
| auto do_enum_snapshot(HANDLE handle, TEntry& entry, TEnumApi&& enumApiFirst, TEnumApi&& enumApiNext, TCallback&& callback) | ||
| { | ||
| if (handle == INVALID_HANDLE_VALUE) | ||
| return E_HANDLE; | ||
|
|
||
| using result_t = decltype(callback(TEntry{})); | ||
| bool enumResult = enumApiFirst(handle, &entry); | ||
| if (!enumResult) | ||
| return E_ABORT; | ||
|
|
||
| do | ||
| { | ||
| if constexpr (wistd::is_void_v<result_t>) | ||
| { | ||
| callback(entry); | ||
| } | ||
| else if constexpr (wistd::is_same_v<result_t, bool>) | ||
| { | ||
| if (callback(entry)) | ||
| return S_OK; | ||
| } | ||
| else | ||
| { | ||
| static_assert( | ||
| [] { | ||
| return false; | ||
| }(), | ||
| "Callback must return void or bool"); | ||
| } | ||
| enumResult = enumApiNext(handle, &entry); | ||
| } while (enumResult); | ||
| return S_OK; | ||
| } | ||
| } // namespace details | ||
|
|
||
| #pragma region Process | ||
| template <typename TCallback> | ||
| auto for_each_process_nothrow(TCallback&& callback) | ||
| { | ||
| PROCESSENTRY32 entry{}; | ||
| entry.dwSize = sizeof(entry); | ||
| return details::do_enum_snapshot( | ||
| unique_handle{CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)}.get(), | ||
| entry, | ||
| &Process32First, | ||
| &Process32Next, | ||
| wistd::forward<TCallback>(callback)); | ||
| } | ||
|
|
||
| template <typename TCallback> | ||
| void for_each_process_failfast(TCallback&& callback) | ||
| { | ||
| FAIL_FAST_IF_FAILED(for_each_process_nothrow(callback)); | ||
| } | ||
|
|
||
| #ifdef WIL_ENABLE_EXCEPTIONS | ||
| template <typename TCallback> | ||
| void for_each_process(TCallback&& callback) | ||
| { | ||
| THROW_IF_FAILED(for_each_process_nothrow(callback)); | ||
| } | ||
| #endif | ||
| #pragma endregion | ||
|
|
||
| #pragma region Thread | ||
| template <typename TCallback> | ||
| auto for_each_system_thread_nothrow(TCallback&& callback) | ||
| { | ||
| THREADENTRY32 entry{}; | ||
| entry.dwSize = sizeof(entry); | ||
| return details::do_enum_snapshot( | ||
| unique_handle{CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0)}.get(), | ||
| entry, | ||
| &Thread32First, | ||
| &Thread32Next, | ||
| wistd::forward<TCallback>(callback)); | ||
| } | ||
|
|
||
| template <typename TCallback> | ||
| void for_each_system_thread_failfast(TCallback&& callback) | ||
| { | ||
| FAIL_FAST_IF_FAILED(for_each_system_thread_nothrow(callback)); | ||
| } | ||
|
|
||
| template <typename TCallback> | ||
| auto for_each_process_thread_nothrow(DWORD pid, TCallback&& callback) | ||
| { | ||
| return for_each_system_thread_nothrow([&](THREADENTRY32 const& entry) { | ||
| if (entry.th32OwnerProcessID == pid) | ||
| callback(entry); | ||
| }); | ||
| } | ||
|
|
||
| template <typename TCallback> | ||
| auto for_each_process_thread_nothrow(TCallback&& callback) | ||
| { | ||
| return for_each_process_thread_nothrow(GetCurrentProcessId(), callback); | ||
| } | ||
|
|
||
| template <typename TCallback> | ||
| void for_each_process_thread_failfast(DWORD pid, TCallback&& callback) | ||
| { | ||
| FAIL_FAST_IF_FAILED(for_each_process_thread_nothrow(pid, callback)); | ||
| } | ||
|
|
||
| template <typename TCallback> | ||
| void for_each_process_thread_failfast(TCallback&& callback) | ||
| { | ||
| FAIL_FAST_IF_FAILED(for_each_process_thread_nothrow(callback)); | ||
| } | ||
|
|
||
| #ifdef WIL_ENABLE_EXCEPTIONS | ||
| template <typename TCallback> | ||
| void for_each_system_thread(TCallback&& callback) | ||
| { | ||
| THROW_IF_FAILED(for_each_system_thread_nothrow(callback)); | ||
| } | ||
|
|
||
| template <typename TCallback> | ||
| void for_each_process_thread(DWORD pid, TCallback&& callback) | ||
| { | ||
| THROW_IF_FAILED(for_each_process_thread_nothrow(pid, callback)); | ||
| } | ||
|
|
||
| template <typename TCallback> | ||
| void for_each_process_thread(TCallback&& callback) | ||
| { | ||
| THROW_IF_FAILED(for_each_process_thread_nothrow(callback)); | ||
| } | ||
|
|
||
| #endif | ||
| #pragma endregion | ||
|
|
||
| #pragma region Module | ||
| template <typename TCallback> | ||
| auto for_each_module_nothrow(DWORD pid, bool include32BitModule, TCallback&& callback) | ||
| { | ||
| MODULEENTRY32 entry{}; | ||
| entry.dwSize = sizeof(entry); | ||
| return details::do_enum_snapshot( | ||
| unique_handle{CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | (include32BitModule ? TH32CS_SNAPMODULE32 : 0), pid)}.get(), | ||
| entry, | ||
| &Module32First, | ||
| &Module32Next, | ||
| wistd::forward<TCallback>(callback)); | ||
| } | ||
|
|
||
| template <typename TCallback> | ||
| auto for_each_module_nothrow(bool include32BitModule, TCallback&& callback) | ||
| { | ||
| return for_each_module_nothrow(0, include32BitModule, callback); | ||
| } | ||
|
|
||
| template <typename TCallback> | ||
| auto for_each_module_nothrow(TCallback&& callback) | ||
| { | ||
| return for_each_module_nothrow(true, callback); | ||
| } | ||
|
|
||
| template <typename TCallback> | ||
| void for_each_module_failfast(DWORD pid, bool include32BitModule, TCallback&& callback) | ||
| { | ||
| FAIL_FAST_IF_FAILED(for_each_module_nothrow(pid, include32BitModule, callback)); | ||
| } | ||
|
|
||
| template <typename TCallback> | ||
| void for_each_module_failfast(bool include32BitModule, TCallback&& callback) | ||
| { | ||
| FAIL_FAST_IF_FAILED(for_each_module_nothrow(0, include32BitModule, callback)); | ||
| } | ||
|
|
||
| template <typename TCallback> | ||
| void for_each_module_failfast(TCallback&& callback) | ||
| { | ||
| FAIL_FAST_IF_FAILED(for_each_module_nothrow(callback)); | ||
| } | ||
|
|
||
| #ifdef WIL_ENABLE_EXCEPTIONS | ||
| template <typename TCallback> | ||
| void for_each_module(DWORD pid, bool include32BitModule, TCallback&& callback) | ||
| { | ||
| THROW_IF_FAILED(for_each_module_nothrow(pid, include32BitModule, callback)); | ||
| } | ||
|
|
||
| template <typename TCallback> | ||
| void for_each_module(bool include32BitModule, TCallback&& callback) | ||
| { | ||
| THROW_IF_FAILED(for_each_module_nothrow(0, include32BitModule, callback)); | ||
| } | ||
|
|
||
| template <typename TCallback> | ||
| void for_each_module(TCallback&& callback) | ||
| { | ||
| THROW_IF_FAILED(for_each_module_nothrow(callback)); | ||
| } | ||
| #endif | ||
| #pragma endregion | ||
|
|
||
| #pragma region HeapList | ||
| template <typename TCallback> | ||
| auto for_each_heap_list_nothrow(DWORD pid, TCallback&& callback) | ||
| { | ||
| HEAPLIST32 entry{}; | ||
| entry.dwSize = sizeof(entry); | ||
| return details::do_enum_snapshot( | ||
| unique_handle{CreateToolhelp32Snapshot(TH32CS_SNAPHEAPLIST, pid)}.get(), | ||
| entry, | ||
| &Heap32ListFirst, | ||
| &Heap32ListNext, | ||
| wistd::forward<TCallback>(callback)); | ||
| } | ||
|
|
||
| template <typename TCallback> | ||
| auto for_each_heap_list_nothrow(TCallback&& callback) | ||
| { | ||
| return for_each_heap_list_nothrow(0, callback); | ||
| } | ||
|
|
||
| template <typename TCallback> | ||
| void for_each_heap_list_failfast(DWORD pid, TCallback&& callback) | ||
| { | ||
| FAIL_FAST_IF_FAILED(for_each_heap_list_nothrow(pid, callback)); | ||
| } | ||
|
|
||
| template <typename TCallback> | ||
| void for_each_heap_list_failfast(TCallback&& callback) | ||
| { | ||
| FAIL_FAST_IF_FAILED(for_each_heap_list_nothrow(callback)); | ||
| } | ||
|
|
||
| #ifdef WIL_ENABLE_EXCEPTIONS | ||
| template <typename TCallback> | ||
| void for_each_heap_list(DWORD pid, TCallback&& callback) | ||
| { | ||
| THROW_IF_FAILED(for_each_heap_list_nothrow(pid, callback)); | ||
| } | ||
|
|
||
| template <typename TCallback> | ||
| void for_each_heap_list(TCallback&& callback) | ||
| { | ||
| THROW_IF_FAILED(for_each_heap_list_nothrow(callback)); | ||
| } | ||
| #endif | ||
| #pragma endregion | ||
|
|
||
| #pragma region Heap | ||
| template <typename TCallback> | ||
| auto for_each_heap_nothrow(DWORD pid, ULONG_PTR heapId, TCallback&& callback) | ||
| { | ||
| using result_t = decltype(callback(HEAPENTRY32{})); | ||
|
|
||
| HEAPENTRY32 entry{}; | ||
| entry.dwSize = sizeof(entry); | ||
|
|
||
| if (!Heap32First(&entry, pid, heapId)) | ||
| return E_ABORT; | ||
|
|
||
| bool enumResult = true; | ||
| do | ||
| { | ||
| if constexpr (wistd::is_void_v<result_t>) | ||
| { | ||
| callback(entry); | ||
| } | ||
| else if constexpr (wistd::is_same_v<result_t, bool>) | ||
| { | ||
| if (callback(entry)) | ||
| return S_OK; | ||
| } | ||
| else | ||
| { | ||
| static_assert( | ||
| [] { | ||
| return false; | ||
| }(), | ||
| "Callback must return void or bool"); | ||
| } | ||
| enumResult = Heap32Next(&entry); | ||
| } while (enumResult); | ||
| return S_OK; | ||
| } | ||
|
|
||
| template <typename TCallback> | ||
| auto for_each_heap_nothrow(ULONG_PTR heapId, TCallback&& callback) | ||
| { | ||
| return for_each_heap_nothrow(GetCurrentProcessId(), heapId, callback); | ||
| } | ||
|
|
||
| template <typename TCallback> | ||
| void for_each_heap_failfast(DWORD pid, ULONG_PTR heapId, TCallback&& callback) | ||
| { | ||
| FAIL_FAST_IF_FAILED(for_each_heap_nothrow(pid, heapId, callback)); | ||
| } | ||
|
|
||
| template <typename TCallback> | ||
| void for_each_heap_failfast(ULONG_PTR heapId, TCallback&& callback) | ||
| { | ||
| FAIL_FAST_IF_FAILED(for_each_heap_nothrow(heapId, callback)); | ||
| } | ||
|
|
||
| #ifdef WIL_ENABLE_EXCEPTIONS | ||
| template <typename TCallback> | ||
| void for_each_heap(DWORD pid, ULONG_PTR heapId, TCallback&& callback) | ||
| { | ||
| THROW_IF_FAILED(for_each_heap_nothrow(pid, heapId, callback)); | ||
| } | ||
|
|
||
| template <typename TCallback> | ||
| void for_each_heap(ULONG_PTR heapId, TCallback&& callback) | ||
| { | ||
| THROW_IF_FAILED(for_each_heap_nothrow(heapId, callback)); | ||
| } | ||
| #endif | ||
| #pragma endregion | ||
| } // namespace wil | ||
|
|
||
| #endif | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| #include "common.h" | ||
| #include <WinUser.h> | ||
| #include <wil/toolhelp32.h> | ||
| #include <cstring> | ||
|
|
||
| TEST_CASE("Toolhelp32", "[EnumProcesses]") | ||
| { | ||
| wil::for_each_process([](PROCESSENTRY32 const& entry) { | ||
| REQUIRE_FALSE(std::strlen(entry.szExeFile) == 0); | ||
| }); | ||
| } | ||
|
|
||
| TEST_CASE("Toolhelp32", "[EnumModules]") | ||
| { | ||
| wil::for_each_module([](MODULEENTRY32 const& entry) { | ||
| REQUIRE_FALSE(std::strlen(entry.szExePath) == 0); | ||
| }); | ||
| } | ||
|
|
||
| TEST_CASE("Toolhelp32", "[EnumThreads]") | ||
| { | ||
| wil::for_each_system_thread([pid = GetCurrentProcessId()](THREADENTRY32 const& entry) { | ||
| if (entry.th32OwnerProcessID == pid) | ||
| { | ||
| REQUIRE_FALSE(entry.th32ThreadID == 0); | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| TEST_CASE("Toolhelp32", "[EnumHeapLists]") | ||
| { | ||
| wil::for_each_heap_list([](HEAPLIST32 const& entry) { | ||
| REQUIRE_FALSE(entry.th32HeapID == 0); | ||
| }); | ||
| } | ||
|
|
||
| TEST_CASE("Toolhelp32", "[EnumHeap]") | ||
| { | ||
| wil::for_each_heap_list([](HEAPLIST32 const& heapListEntry) { | ||
| REQUIRE_FALSE(heapListEntry.th32HeapID == 0); | ||
| wil::for_each_heap(heapListEntry.th32HeapID, [](HEAPENTRY32 const& heapEntry) { | ||
| REQUIRE_FALSE(heapEntry.dwAddress == 0); | ||
| }); | ||
| return false; | ||
| }); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.