Skip to content

Instantly share code, notes, and snippets.

@lhecker

lhecker/main.cpp Secret

Last active May 27, 2024 17:08
Show Gist options
  • Save lhecker/82b029643e9f9ccf15304a623093880b to your computer and use it in GitHub Desktop.
Save lhecker/82b029643e9f9ccf15304a623093880b to your computer and use it in GitHub Desktop.
Debug HWND reference count via EVENT_OBJECT_CREATE and EVENT_OBJECT_DESTROY
#include <Windows.h>
#include <cstdio>
#include <format>
#include <map>
#include <unordered_set>
struct insensitive_less {
using is_transparent = int;
bool operator()(const std::wstring_view& lhs, const std::wstring_view& rhs) const noexcept {
const auto lhsLen = static_cast<int>(lhs.size());
const auto rhsLen = static_cast<int>(rhs.size());
return CompareStringOrdinal(lhs.data(), lhsLen, rhs.data(), rhsLen, TRUE) == CSTR_LESS_THAN;
}
};
static std::map<std::wstring, std::unordered_set<HWND>, insensitive_less> g_windows;
int main() {
SetConsoleOutputCP(CP_UTF8);
SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN);
SetWinEventHook(
EVENT_OBJECT_CREATE,
EVENT_OBJECT_DESTROY,
nullptr,
[](HWINEVENTHOOK hWinEventHook, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD idEventThread, DWORD dwmsEventTime) {
if (!hwnd || idObject != 0) {
return;
}
wchar_t pathBuf[4096];
DWORD pathLen = 0;
if (DWORD pid; GetWindowThreadProcessId(hwnd, &pid) != 0) {
if (const auto handle = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid)) {
pathLen = ARRAYSIZE(pathBuf);
if (!QueryFullProcessImageNameW(handle, 0, &pathBuf[0], &pathLen)) {
pathLen = 0;
}
CloseHandle(handle);
}
}
std::wstring_view path{&pathBuf[0], pathLen};
std::wstring_view filename;
if (const auto sep = path.find_last_of(L"/\\"); sep != std::wstring_view::npos) {
filename = path.substr(sep + 1);
}
if (event == EVENT_OBJECT_CREATE) {
if (!filename.empty()) {
const auto it = g_windows.emplace(std::piecewise_construct, std::forward_as_tuple(filename), std::forward_as_tuple()).first;
it->second.emplace(hwnd);
}
} else {
for (auto& pair : g_windows) {
pair.second.erase(hwnd);
}
std::erase_if(g_windows, [](const auto& pair) { return pair.second.empty(); });
}
std::wstring buffer;
buffer.append(L"\x1b[H\x1b[J"); // clear screen
for (const auto& pair : g_windows) {
std::format_to(std::back_inserter(buffer), L"{}: {}\r\n", pair.first, pair.second.size());
}
WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), buffer.data(), static_cast<DWORD>(buffer.size()), nullptr, nullptr);
},
0,
0,
WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS
);
for (;;) {
MSG msg;
if (GetMessageW(&msg, nullptr, 0, 0) <= 0) {
break;
}
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment