diff dep/animone/src/win/win32.cc @ 258:862d0d8619f6

*: HUUUGE changes animia has been renamed to animone, so instead of thinking of a health condition, you think of a beautiful flower :) I've also edited some of the code for animone, but I have no idea if it even works or not because I don't have a mac or windows machine lying around. whoops! ... anyway, all of the changes divergent from Anisthesia are now licensed under BSD. it's possible that I could even rewrite most of the code to where I don't even have to keep the MIT license, but that's thinking too far into the future I've been slacking off on implementing the anime seasons page, mostly out of laziness. I think I'd have to create another db file specifically for the seasons anyway, this code is being pushed *primarily* because the hard drive it's on is failing! yay :)
author Paper <paper@paper.us.eu.org>
date Mon, 01 Apr 2024 02:43:44 -0400
parents
children 09c5bd74fe93
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/animone/src/win/win32.cc	Mon Apr 01 02:43:44 2024 -0400
@@ -0,0 +1,143 @@
+/*
+ * win/win32.cc: support for Windows
+ *
+ * Surprisingly, this is the one time where Microsoft actually
+ * does it fairly OK. Everything has a pretty simple API, despite
+ * the stupid wide string stuff.
+ */
+#include "animone/win/win32.h"
+#include "animone.h"
+#include "animone/util/win32.h"
+#include "animone/win.h"
+
+#include <set>
+#include <string>
+
+#include <windows.h>
+
+namespace animone::internal::win32 {
+
+static std::wstring GetWindowClassName(HWND hwnd) {
+	static constexpr int kMaxSize = 256;
+
+	std::wstring buffer(kMaxSize, L'\0');
+	const auto size = ::GetClassNameW(hwnd, &buffer.front(), buffer.length());
+	buffer.resize(size);
+	return buffer;
+}
+
+static std::wstring GetWindowText(HWND hwnd) {
+	const auto estimated_size = ::GetWindowTextLengthW(hwnd);
+	std::wstring buffer(estimated_size + 1, L'\0');
+
+	const auto size = ::GetWindowTextW(hwnd, &buffer.front(), buffer.length());
+	/* GetWindowTextLength docs:
+	 * "Under certain conditions, the GetWindowTextLength function may return a value
+	 *  that is larger than the actual length of the text." */
+	buffer.resize(size);
+	return buffer;
+}
+
+static DWORD GetWindowProcessId(HWND hwnd) {
+	DWORD process_id = 0;
+	::GetWindowThreadProcessId(hwnd, &process_id);
+	return process_id;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+static bool VerifyWindowStyle(HWND hwnd) {
+	const auto window_style = ::GetWindowLong(hwnd, GWL_STYLE);
+	const auto window_ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
+
+	auto has_style = [&window_style](DWORD style) { return (window_style & style) != 0; };
+	auto has_ex_style = [&window_ex_style](DWORD ex_style) { return (window_ex_style & ex_style) != 0; };
+
+	// Toolbars, tooltips and similar topmost windows
+	if (has_style(WS_POPUP) && has_ex_style(WS_EX_TOOLWINDOW))
+		return false;
+	if (has_ex_style(WS_EX_TOPMOST) && has_ex_style(WS_EX_TOOLWINDOW))
+		return false;
+
+	return true;
+}
+
+static bool VerifyClassName(const std::wstring& name) {
+	static const std::set<std::wstring> invalid_names = {
+	    // System classes
+	    L"#32770",        // Dialog box
+	    L"CabinetWClass", // Windows Explorer
+	    L"ComboLBox",
+	    L"DDEMLEvent",
+	    L"DDEMLMom",
+	    L"DirectUIHWND",
+	    L"GDI+ Hook Window Class",
+	    L"IME",
+	    L"Internet Explorer_Hidden",
+	    L"MSCTFIME UI",
+	    L"tooltips_class32",
+	};
+
+	return !name.empty() && !invalid_names.count(name);
+}
+
+static bool VerifyProcessPath(const std::wstring& path) {
+	return !path.empty() && !IsSystemDirectory(path);
+}
+
+static bool VerifyProcessFileName(const std::wstring& name) {
+	static const std::set<std::wstring> invalid_names = {
+	    // System files
+	    L"explorer",   // Windows Explorer
+	    L"taskeng",    // Task Scheduler Engine
+	    L"taskhost",   // Host Process for Windows Tasks
+	    L"taskhostex", // Host Process for Windows Tasks
+	    L"Taskmgr",    // Task Manager
+	};
+
+	return !name.empty() && !invalid_names.count(name);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+static BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM param) {
+	if (!::IsWindowVisible(hwnd))
+		return TRUE;
+
+	if (!VerifyWindowStyle(hwnd))
+		return TRUE;
+
+	Window window;
+	window.id = static_cast<unsigned int>(reinterpret_cast<ULONG_PTR>(hwnd));
+	window.text = ToUtf8String(GetWindowText(hwnd));
+
+	{
+		std::wstring class_name = GetWindowClassName(hwnd);
+		window.class_name = ToUtf8String(class_name);
+		if (!VerifyClassName(class_name))
+			return TRUE;
+	}
+
+	Process process;
+	process.pid = GetWindowProcessId(hwnd);
+	process.name = fd::GetProcessName(process.pid)
+
+	    auto& window_proc = *reinterpret_cast<window_proc_t*>(param);
+	if (!window_proc(process, window))
+		return FALSE;
+
+	return TRUE;
+}
+
+bool EnumerateWindows(window_proc_t window_proc) {
+	if (!window_proc)
+		return false;
+
+	const auto param = reinterpret_cast<LPARAM>(&window_proc);
+
+	// Note that EnumWindows enumerates only top-level windows of desktop apps
+	// (as opposed to UWP apps) on Windows 8 and above.
+	return ::EnumWindows(EnumWindowsProc, param) != FALSE;
+}
+
+} // namespace animone::internal::win32