annotate dep/animone/src/win/win32.cc @ 326:10096c5489e3

anime/db: refactor anime_season_db out
author Paper <paper@paper.us.eu.org>
date Thu, 13 Jun 2024 00:42:00 -0400
parents b1f625b0227c
children a7d4e5107531
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
301
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
1 /*
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
2 * win/win32.cc: support for Windows
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
3 *
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
4 * Surprisingly, this is the one time where Microsoft actually
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
5 * does it fairly OK. Everything has a pretty simple API, despite
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
6 * the stupid wide string stuff.
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
7 */
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
8 #include "animone/win/win32.h"
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
9 #include "animone.h"
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
10 #include "animone/util/win32.h"
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
11 #include "animone/win.h"
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
12 #include "animone/fd.h"
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
13
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
14 #include <set>
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
15 #include <string>
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
16
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
17 #include <windows.h>
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
18
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
19 namespace animone::internal::win32 {
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
20
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
21 static std::wstring GetWindowClassName(HWND hwnd) {
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
22 static constexpr int kMaxSize = 256;
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
23
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
24 std::wstring buffer(kMaxSize, L'\0');
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
25 const auto size = ::GetClassNameW(hwnd, &buffer.front(), buffer.length());
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
26 buffer.resize(size);
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
27 return buffer;
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
28 }
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
29
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
30 static std::wstring GetWindowText(HWND hwnd) {
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
31 const auto estimated_size = ::GetWindowTextLengthW(hwnd);
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
32 std::wstring buffer(estimated_size + 1, L'\0');
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
33
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
34 const auto size = ::GetWindowTextW(hwnd, &buffer.front(), buffer.length());
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
35 /* GetWindowTextLength docs:
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
36 * "Under certain conditions, the GetWindowTextLength function may return a value
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
37 * that is larger than the actual length of the text." */
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
38 buffer.resize(size);
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
39 return buffer;
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
40 }
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
41
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
42 static DWORD GetWindowProcessId(HWND hwnd) {
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
43 DWORD process_id = 0;
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
44 ::GetWindowThreadProcessId(hwnd, &process_id);
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
45 return process_id;
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
46 }
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
47
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
48 ////////////////////////////////////////////////////////////////////////////////
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
49
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
50 static bool VerifyWindowStyle(HWND hwnd) {
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
51 const auto window_style = ::GetWindowLong(hwnd, GWL_STYLE);
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
52 const auto window_ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
53
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
54 auto has_style = [&window_style](DWORD style) { return (window_style & style) != 0; };
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
55 auto has_ex_style = [&window_ex_style](DWORD ex_style) { return (window_ex_style & ex_style) != 0; };
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
56
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
57 // Toolbars, tooltips and similar topmost windows
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
58 if (has_style(WS_POPUP) && has_ex_style(WS_EX_TOOLWINDOW))
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
59 return false;
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
60 if (has_ex_style(WS_EX_TOPMOST) && has_ex_style(WS_EX_TOOLWINDOW))
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
61 return false;
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
62
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
63 return true;
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
64 }
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
65
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
66 static bool VerifyClassName(const std::wstring& name) {
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
67 static const std::set<std::wstring> invalid_names = {
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
68 // System classes
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
69 L"#32770", // Dialog box
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
70 L"CabinetWClass", // Windows Explorer
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
71 L"ComboLBox",
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
72 L"DDEMLEvent",
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
73 L"DDEMLMom",
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
74 L"DirectUIHWND",
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
75 L"GDI+ Hook Window Class",
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
76 L"IME",
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
77 L"Internet Explorer_Hidden",
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
78 L"MSCTFIME UI",
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
79 L"tooltips_class32",
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
80 };
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
81
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
82 return !name.empty() && !invalid_names.count(name);
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
83 }
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
84
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
85 static bool VerifyProcessPath(const std::wstring& path) {
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
86 return !path.empty() && !IsSystemDirectory(path);
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
87 }
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
88
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
89 static bool VerifyProcessFileName(const std::wstring& name) {
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
90 static const std::set<std::wstring> invalid_names = {
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
91 // System files
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
92 L"explorer", // Windows Explorer
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
93 L"taskeng", // Task Scheduler Engine
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
94 L"taskhost", // Host Process for Windows Tasks
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
95 L"taskhostex", // Host Process for Windows Tasks
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
96 L"Taskmgr", // Task Manager
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
97 };
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
98
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
99 return !name.empty() && !invalid_names.count(name);
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
100 }
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
101
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
102 ////////////////////////////////////////////////////////////////////////////////
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
103
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
104 static BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM param) {
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
105 if (!::IsWindowVisible(hwnd))
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
106 return TRUE;
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
107
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
108 if (!VerifyWindowStyle(hwnd))
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
109 return TRUE;
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
110
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
111 Window window;
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
112 window.id = static_cast<unsigned int>(reinterpret_cast<ULONG_PTR>(hwnd));
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
113 window.text = ToUtf8String(GetWindowText(hwnd));
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
114
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
115 {
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
116 std::wstring class_name = GetWindowClassName(hwnd);
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
117 window.class_name = ToUtf8String(class_name);
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
118 if (!VerifyClassName(class_name))
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
119 return TRUE;
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
120 }
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
121
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
122 Process process;
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
123 process.pid = GetWindowProcessId(hwnd);
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
124 GetProcessName(process.pid, process.name);
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
125
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
126 auto& window_proc = *reinterpret_cast<window_proc_t*>(param);
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
127 if (!window_proc(process, window))
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
128 return FALSE;
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
129
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
130 return TRUE;
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
131 }
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
132
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
133 bool EnumerateWindows(window_proc_t window_proc) {
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
134 if (!window_proc)
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
135 return false;
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
136
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
137 const auto param = reinterpret_cast<LPARAM>(&window_proc);
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
138
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
139 // Note that EnumWindows enumerates only top-level windows of desktop apps
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
140 // (as opposed to UWP apps) on Windows 8 and above.
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
141 return ::EnumWindows(EnumWindowsProc, param) != FALSE;
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
142 }
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
143
b1f625b0227c *: convert all files CRLF -> LF
Paper <paper@paper.us.eu.org>
parents: 267
diff changeset
144 } // namespace animone::internal::win32