|
#pragma once |
|
|
|
#include <iterator> |
|
#include <stdexcept> |
|
#include <type_traits> |
|
#include <utility> |
|
#include <memory> |
|
#include <cstddef> |
|
#include <Windows.h> |
|
#include <TlHelp32.h> |
|
|
|
template <DWORD dwFlag> |
|
class snapshot; |
|
|
|
// Generic snapshot iterator |
|
// |
|
// Template parameters: |
|
// dwFlag: Flag that indicate the type of this iterator. One of TH32CS_SNAPHEAPLIST, TH32CS_SNAPMODULE, TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, TH32CS_SNAPPROCESS or TH32CS_SNAPTHREAD. |
|
// StructType: The type of structure used by FirstFunc and NextFunc. One of HEAPLIST32, MODULEENTRY32, PROCESSENTRY32 or THREADENTRY32 corresponding to dwFlag. |
|
// FirstFunc: Win32 API used to retrieve information from snapshot handle. One of Heap32ListFirst, Module32First, Process32First or Thread32First. |
|
// NextFunc: Win32 API used to retrieve succeeding information from snapshot handle. One of Heap32ListNext, Module32Next, Process32Next or Thread32Next. |
|
template <DWORD dwFlag, typename StructType, BOOL(WINAPI* FirstFunc)(HANDLE, StructType*), BOOL(WINAPI* NextFunc)(HANDLE, StructType*)> |
|
class snapshot_iterator |
|
{ |
|
public: |
|
static_assert(!(dwFlag == 0), "Invalid snapshot iterator."); |
|
static_assert(dwFlag == TH32CS_SNAPHEAPLIST || dwFlag == TH32CS_SNAPMODULE || dwFlag == (TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32) || dwFlag == TH32CS_SNAPPROCESS || dwFlag == TH32CS_SNAPTHREAD, |
|
"dwFlag must be TH32CS_SNAPHEAPLIST, TH32CS_SNAPMODULE, TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, TH32CS_SNAPPROCESS or TH32CS_SNAPTHREAD."); |
|
|
|
friend class snapshot<dwFlag>; // Make snapshot<dwType> friend to allow it to access private constructor |
|
|
|
using iterator_category = std::input_iterator_tag; // Iterator category: input iterator |
|
using value_type = const StructType; // value_type, pointer and reference are all const-qualified to prohibit modification |
|
using difference_type = std::ptrdiff_t; |
|
using pointer = const value_type*; |
|
using reference = const value_type&; |
|
static constexpr DWORD flag = dwFlag; |
|
using structure_type = StructType; |
|
static constexpr BOOL(WINAPI* first_function)(HANDLE, StructType*) = FirstFunc; |
|
static constexpr BOOL(WINAPI* next_function)(HANDLE, StructType*) = NextFunc; |
|
|
|
snapshot_iterator(const snapshot_iterator& other) = default; |
|
snapshot_iterator& operator=(const snapshot_iterator& other) = default; |
|
reference operator*() const; |
|
snapshot_iterator& operator++(); |
|
snapshot_iterator operator++(int); |
|
snapshot_iterator* operator->() const; |
|
template <DWORD dwFlag2, typename StructType2, BOOL(WINAPI* FirstFunc2)(HANDLE, StructType2*), BOOL(WINAPI* NextFunc2)(HANDLE, StructType2*)> |
|
friend bool operator==(const snapshot_iterator<dwFlag2, StructType2, FirstFunc2, NextFunc2>& lhs, const snapshot_iterator<dwFlag2, StructType2, FirstFunc2, NextFunc2>& rhs); |
|
template <DWORD dwFlag2, typename StructType2, BOOL(WINAPI* FirstFunc2)(HANDLE, StructType2*), BOOL(WINAPI* NextFunc2)(HANDLE, StructType2*)> |
|
friend void swap(snapshot_iterator<dwFlag2, StructType2, FirstFunc2, NextFunc2>& lhs, snapshot_iterator<dwFlag2, StructType2, FirstFunc2, NextFunc2>& rhs) noexcept; |
|
private: |
|
snapshot_iterator(const HANDLE snapshot_handle); // Private constructor for snapshot<dwFlag> to use |
|
HANDLE m_snapshot_handle; // Snapshot handle |
|
StructType m_structure; |
|
std::size_t m_position; // Stores the position of the iterator for operator== |
|
}; |
|
|
|
// Alias templates of snapshot_iterator |
|
using heap_list_iterator = snapshot_iterator<TH32CS_SNAPHEAPLIST, HEAPLIST32, Heap32ListFirst, Heap32ListNext>; |
|
using module_iterator = snapshot_iterator<TH32CS_SNAPMODULE, MODULEENTRY32, Module32First, Module32Next>; |
|
using module32_iterator = snapshot_iterator<TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, MODULEENTRY32, Module32First, Module32Next>; |
|
using process_iterator = snapshot_iterator<TH32CS_SNAPPROCESS, PROCESSENTRY32, Process32First, Process32Next>; |
|
using thread_iterator = snapshot_iterator<TH32CS_SNAPTHREAD, THREADENTRY32, Thread32First, Thread32Next>; |
|
using null_iterator = snapshot_iterator<0, void, nullptr, nullptr>; |
|
|
|
// Snapshot container class |
|
// |
|
// Template parameter: |
|
// dwFlag: Flag that indicate the type of this container. One of TH32CS_SNAPHEAPLIST, TH32CS_SNAPMODULE, TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, TH32CS_SNAPPROCESS or TH32CS_SNAPTHREAD. |
|
template <DWORD dwFlag> |
|
class snapshot |
|
{ |
|
public: |
|
static_assert(dwFlag == TH32CS_SNAPHEAPLIST || dwFlag == TH32CS_SNAPMODULE || dwFlag == (TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32) || dwFlag == TH32CS_SNAPPROCESS || dwFlag == TH32CS_SNAPTHREAD, |
|
"dwFlag must be TH32CS_SNAPHEAPLIST, TH32CS_SNAPMODULE, TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, TH32CS_SNAPPROCESS or TH32CS_SNAPTHREAD."); |
|
|
|
// Iterator type corresponding to dwFlag |
|
using iterator = std::conditional_t<dwFlag == TH32CS_SNAPHEAPLIST, heap_list_iterator, |
|
std::conditional_t<dwFlag == TH32CS_SNAPMODULE, module_iterator, |
|
std::conditional_t<dwFlag == (TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32), module32_iterator, |
|
std::conditional_t<dwFlag == TH32CS_SNAPPROCESS, process_iterator, |
|
std::conditional_t<dwFlag == TH32CS_SNAPTHREAD, thread_iterator, null_iterator>>>>>; |
|
using const_iterator = iterator; |
|
using size_type = std::size_t; |
|
using difference_type = std::ptrdiff_t; |
|
using value_type = iterator::value_type; |
|
using pointer = iterator::pointer; |
|
using const_pointer = pointer; |
|
using reference = iterator::reference; |
|
using const_reference = reference; |
|
using iterator_category = std::input_iterator_tag; |
|
static constexpr DWORD flag = dwFlag; |
|
|
|
snapshot(DWORD th32ProcessID = NULL); |
|
snapshot(const snapshot&) = delete; // snapshot class is move only |
|
snapshot& operator=(const snapshot&) = delete; |
|
snapshot& operator=(snapshot&&) = default; |
|
iterator begin() noexcept; |
|
const_iterator begin() const noexcept; |
|
const_iterator cbegin() const noexcept; |
|
iterator end() noexcept; |
|
const_iterator end() const noexcept; |
|
const_iterator cend() const noexcept; |
|
template <DWORD dwFlag2> |
|
friend bool operator==(const snapshot<dwFlag2>& lhs, const snapshot<dwFlag2>& rhs); |
|
template <DWORD dwFlag2> |
|
friend void swap(snapshot<dwFlag2>& lhs, snapshot<dwFlag2>& rhs) noexcept; |
|
private: |
|
struct win32_handle_deleter |
|
{ |
|
using pointer = HANDLE; |
|
void operator()(HANDLE h) |
|
{ |
|
CloseHandle(h); |
|
} |
|
}; |
|
std::unique_ptr<HANDLE, win32_handle_deleter> m_snapshot_handle; |
|
}; |
|
|
|
// snapshot_iterator methods and friend functions |
|
|
|
template<DWORD dwFlag, typename StructType, BOOL(WINAPI* FirstFunc)(HANDLE, StructType*), BOOL(WINAPI* NextFunc)(HANDLE, StructType*)> |
|
inline snapshot_iterator<dwFlag, StructType, FirstFunc, NextFunc>::snapshot_iterator(const HANDLE snapshot_handle) : m_snapshot_handle(snapshot_handle), m_structure(), m_position(0) |
|
{ |
|
if (m_snapshot_handle) |
|
{ |
|
m_structure.dwSize = sizeof(value_type); |
|
if (!FirstFunc(m_snapshot_handle, &m_structure)) |
|
{ |
|
if (GetLastError() != ERROR_NO_MORE_FILES) |
|
{ |
|
throw(std::runtime_error("Failed to enumerator on snapshot handle!")); |
|
} |
|
else |
|
{ |
|
m_snapshot_handle = NULL; |
|
} |
|
} |
|
} |
|
} |
|
|
|
template<DWORD dwFlag, typename StructType, BOOL(WINAPI* FirstFunc)(HANDLE, StructType*), BOOL(WINAPI* NextFunc)(HANDLE, StructType*)> |
|
inline typename snapshot_iterator<dwFlag, StructType, FirstFunc, NextFunc>::reference snapshot_iterator<dwFlag, StructType, FirstFunc, NextFunc>::operator*() const |
|
{ |
|
return m_structure; |
|
} |
|
|
|
template<DWORD dwFlag, typename StructType, BOOL(WINAPI* FirstFunc)(HANDLE, StructType*), BOOL(WINAPI* NextFunc)(HANDLE, StructType*)> |
|
inline snapshot_iterator<dwFlag, StructType, FirstFunc, NextFunc>& snapshot_iterator<dwFlag, StructType, FirstFunc, NextFunc>::operator++() |
|
{ |
|
if (!NextFunc(m_snapshot_handle, &m_structure)) |
|
{ |
|
if (GetLastError() != ERROR_NO_MORE_FILES) |
|
{ |
|
throw(std::runtime_error("Failed to enumerator on snapshot handle!")); |
|
} |
|
else |
|
{ |
|
m_snapshot_handle = NULL; |
|
} |
|
} |
|
return *this; |
|
} |
|
|
|
template<DWORD dwFlag, typename StructType, BOOL(WINAPI* FirstFunc)(HANDLE, StructType*), BOOL(WINAPI* NextFunc)(HANDLE, StructType*)> |
|
inline snapshot_iterator<dwFlag, StructType, FirstFunc, NextFunc> snapshot_iterator<dwFlag, StructType, FirstFunc, NextFunc>::operator++(int) |
|
{ |
|
snapshot_iterator tmp{ *this }; |
|
if (!NextFunc(m_snapshot_handle, &m_structure)) |
|
{ |
|
if (GetLastError() != ERROR_NO_MORE_FILES) |
|
{ |
|
throw(std::runtime_error("Failed to enumerator on snapshot handle!")); |
|
} |
|
else |
|
{ |
|
m_snapshot_handle = NULL; |
|
} |
|
} |
|
return tmp; |
|
} |
|
|
|
template<DWORD dwFlag, typename StructType, BOOL(WINAPI* FirstFunc)(HANDLE, StructType*), BOOL(WINAPI* NextFunc)(HANDLE, StructType*)> |
|
inline snapshot_iterator<dwFlag, StructType, FirstFunc, NextFunc>* snapshot_iterator<dwFlag, StructType, FirstFunc, NextFunc>::operator->() const |
|
{ |
|
return &(this->operator*()); |
|
} |
|
|
|
template<DWORD dwFlag, typename StructType, BOOL(WINAPI* FirstFunc)(HANDLE, StructType*), BOOL(WINAPI* NextFunc)(HANDLE, StructType*)> |
|
inline bool operator==(const snapshot_iterator<dwFlag, StructType, FirstFunc, NextFunc>& lhs, const snapshot_iterator<dwFlag, StructType, FirstFunc, NextFunc>& rhs) |
|
{ |
|
if (!lhs.m_snapshot_handle && !rhs.m_snapshot_handle) |
|
{ |
|
return true; |
|
} |
|
else if (lhs.m_snapshot_handle == rhs.m_snapshot_handle && lhs.m_position == rhs.m_position) |
|
{ |
|
return true; |
|
} |
|
else |
|
{ |
|
return false; |
|
} |
|
} |
|
|
|
template<DWORD dwFlag, typename StructType, BOOL(WINAPI* FirstFunc)(HANDLE, StructType*), BOOL(WINAPI* NextFunc)(HANDLE, StructType*)> |
|
inline void swap(snapshot_iterator<dwFlag, StructType, FirstFunc, NextFunc>& lhs, snapshot_iterator<dwFlag, StructType, FirstFunc, NextFunc>& rhs) noexcept |
|
{ |
|
using std::swap; |
|
swap(lhs.m_snapshot_handle, rhs.m_snapshot_handle); |
|
swap(lhs.m_structure, rhs.m_structure); |
|
swap(lhs.m_position, rhs.m_position); |
|
} |
|
|
|
// snapshot methods and friend functions |
|
|
|
template <DWORD dwFlag> |
|
inline snapshot<dwFlag>::snapshot(DWORD th32ProcessID) : m_snapshot_handle(CreateToolhelp32Snapshot(dwFlag, th32ProcessID), win32_handle_deleter{}) |
|
{ |
|
if (!m_snapshot_handle) |
|
{ |
|
throw(std::runtime_error("Failed to create snapshot handle!")); |
|
} |
|
} |
|
|
|
template <DWORD dwFlag> |
|
inline snapshot<dwFlag>::iterator snapshot<dwFlag>::begin() noexcept |
|
{ |
|
return this->cbegin(); |
|
} |
|
|
|
template <DWORD dwFlag> |
|
inline snapshot<dwFlag>::iterator snapshot<dwFlag>::begin() const noexcept |
|
{ |
|
return this->cbegin(); |
|
} |
|
|
|
template<DWORD dwFlag> |
|
inline snapshot<dwFlag>::const_iterator snapshot<dwFlag>::cbegin() const noexcept |
|
{ |
|
return iterator(m_snapshot_handle.get()); |
|
} |
|
|
|
template <DWORD dwFlag> |
|
inline snapshot<dwFlag>::iterator snapshot<dwFlag>::end() noexcept |
|
{ |
|
return this->cend(); |
|
} |
|
|
|
template <DWORD dwFlag> |
|
inline snapshot<dwFlag>::iterator snapshot<dwFlag>::end() const noexcept |
|
{ |
|
return this->cend(); |
|
} |
|
|
|
template <DWORD dwFlag> |
|
inline snapshot<dwFlag>::const_iterator snapshot<dwFlag>::cend() const noexcept |
|
{ |
|
return iterator(NULL); |
|
} |
|
|
|
template <DWORD dwFlag> |
|
inline bool operator==(const snapshot<dwFlag>& lhs, const snapshot<dwFlag>& rhs) |
|
{ |
|
return lhs.m_snapshot_handle == rhs.m_snapshot_handle; |
|
} |
|
|
|
template <DWORD dwFlag> |
|
inline void swap(snapshot<dwFlag>& lhs, snapshot<dwFlag>& rhs) noexcept |
|
{ |
|
using std::swap; |
|
swap(lhs.m_snapshot_handle, rhs.m_snapshot_handle); |
|
} |