Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save seiren-naru-shirayuri/853a912dedd795213f1cae0d09bfbde1 to your computer and use it in GitHub Desktop.
Save seiren-naru-shirayuri/853a912dedd795213f1cae0d09bfbde1 to your computer and use it in GitHub Desktop.
A C++ wrapper around WIN32 API CreateToolhelp32Snapshot
!CreateToolhelp32SnapshotCppWrapper

A C++ wrapper around WIN32 API CreateToolhelp32Snapshot.

This gist is released under GLWTPL.

#pragma once
#include <string>
#include <string_view>
#include <type_traits>
#include <cctype>
#include <cwctype>
// always_false helper class for if constexpr
template <typename ...>
struct always_false : std::false_type {};
template <typename ...Ts>
inline constexpr bool always_false_v = always_false<Ts...>::value;
// Case insensitive char traits
template <typename CharT>
struct case_insensitive_char_traits : std::char_traits<CharT>
{
public:
static bool eq(CharT lhs, CharT rhs)
{
return to_upper(lhs) == to_upper(rhs);
}
static bool lt(CharT lhs, CharT rhs)
{
return to_upper(lhs) < to_upper(rhs);
}
static int compare(const CharT* str1, const CharT* str2, std::size_t length)
{
while (length-- != 0)
{
if (to_upper(*str1) < to_upper(*str2))
{
return -1;
}
if (to_upper(*str1) > to_upper(*str2))
{
return 1;
}
++str1;
++str2;
}
return 0;
}
static const CharT* find(const CharT* str, std::size_t length, CharT ch)
{
auto upper_char{ to_upper(ch) };
while (length-- != 0)
{
if (to_upper(*str) == upper_char)
{
return str;
}
str++;
}
return nullptr;
}
private:
static auto to_upper(CharT ch)
{
if constexpr (std::is_same_v<CharT, char>)
{
return std::toupper(ch);
}
else if constexpr (std::is_same_v<CharT, wchar_t>)
{
return std::towupper(ch);
}
else
{
static_assert(always_false_v<CharT>, "CharT must be either char or wchar_t.");
}
}
};
using case_insensitive_string = std::basic_string<char, case_insensitive_char_traits<char>>; // Case insensitive counterpart of std::string
using case_insensitive_wstring = std::basic_string<wchar_t, case_insensitive_char_traits<wchar_t>>; // Case insensitive counterpart of std::wstring
using case_insensitive_string_view = std::basic_string_view<char, case_insensitive_char_traits<char>>; // Case insensitive counterpart of std::string_view
using case_insensitive_wstring_view = std::basic_string_view<wchar_t, case_insensitive_char_traits<wchar_t>>; // case insensitive counterpart of std::wstring_view
#define WIN32_LEAN_AND_MEAN
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <Windows.h>
#include <TlHelp32.h>
#include <io.h>
#include <fcntl.h>
#include "snapshot_iterators.h"
#include "case_insensitive_string.h"
// Example: list all processes and find if Chrome is running.
int main()
{
if (_setmode(_fileno(stdout), _O_WTEXT) != -1)
{
snapshot<TH32CS_SNAPPROCESS> s;
std::wcout << L"Processes (PID):\n\n";
for (const auto& i : s)
{
std::wcout << i.szExeFile << " (" << i.th32ProcessID << ")\n";
}
std::wcout << std::endl;
auto&& iter = std::find_if(s.begin(), s.end(), [](decltype(s)::const_reference r) { return case_insensitive_wstring_view(r.szExeFile) == case_insensitive_wstring_view(L"CHROME.EXE"); });
if (iter != s.end())
{
std::wcout << L"Chrome is running." << std::endl;
}
else
{
std::wcout << L"Chrome is not running." << std::endl;
}
}
else
{
return EXIT_FAILURE;
}
}
#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);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment