Mercurial > minori
comparison dep/animia/src/win/win32.cc @ 152:8700806c2cc2
dep/animia: awesome new breaking changes!
I'm so tired
author | Paper <mrpapersonic@gmail.com> |
---|---|
date | Wed, 15 Nov 2023 02:34:59 -0500 |
parents | |
children | bd439dd6ffc5 |
comparison
equal
deleted
inserted
replaced
151:54744a48a7d7 | 152:8700806c2cc2 |
---|---|
1 #include "animia/win/win32.h" | |
2 #include "animia/util/win32.h" | |
3 #include "animia/win.h" | |
4 #include "animia.h" | |
5 | |
6 #include <set> | |
7 #include <string> | |
8 | |
9 #include <windows.h> | |
10 | |
11 namespace animia::internal::win32 { | |
12 | |
13 static std::wstring GetWindowClassName(HWND hwnd) { | |
14 // The maximum size for lpszClassName, according to the documentation of | |
15 // WNDCLASSEX structure | |
16 constexpr int kMaxSize = 256; | |
17 | |
18 std::wstring buffer(kMaxSize, L'\0'); | |
19 const auto size = ::GetClassNameW(hwnd, &buffer.front(), buffer.length()); | |
20 return buffer; | |
21 } | |
22 | |
23 static std::wstring GetWindowText(HWND hwnd) { | |
24 const int size = ::GetWindowTextLengthW(hwnd); | |
25 | |
26 std::wstring buffer(size, L'\0'); | |
27 ::GetWindowTextW(hwnd, &buffer.front(), buffer.length()); | |
28 return buffer; | |
29 } | |
30 | |
31 static DWORD GetWindowProcessId(HWND hwnd) { | |
32 DWORD process_id = 0; | |
33 ::GetWindowThreadProcessId(hwnd, &process_id); | |
34 return process_id; | |
35 } | |
36 | |
37 static std::wstring GetProcessPath(DWORD process_id) { | |
38 // If we try to open a SYSTEM process, this function fails and the last error | |
39 // code is ERROR_ACCESS_DENIED. | |
40 // | |
41 // Note that if we requested PROCESS_QUERY_INFORMATION access right instead | |
42 // of PROCESS_QUERY_LIMITED_INFORMATION, this function would fail when used | |
43 // to open an elevated process. | |
44 Handle process_handle(::OpenProcess( | |
45 PROCESS_QUERY_LIMITED_INFORMATION, FALSE, process_id)); | |
46 | |
47 if (!process_handle) | |
48 return std::wstring(); | |
49 | |
50 std::wstring buffer(MAX_PATH, L'\0'); | |
51 DWORD buf_size = buffer.length(); | |
52 | |
53 // Note that this function requires Windows Vista or above. You may use | |
54 // GetProcessImageFileName or GetModuleFileNameEx on earlier versions. | |
55 if (!::QueryFullProcessImageNameW(process_handle.get(), 0, &buffer.front(), &buf_size)) | |
56 return std::wstring(); | |
57 | |
58 return buffer.substr(0, buf_size + 1); | |
59 } | |
60 | |
61 //////////////////////////////////////////////////////////////////////////////// | |
62 | |
63 static bool VerifyWindowStyle(HWND hwnd) { | |
64 const auto window_style = ::GetWindowLong(hwnd, GWL_STYLE); | |
65 const auto window_ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE); | |
66 | |
67 auto has_style = [&window_style](DWORD style) { | |
68 return (window_style & style) != 0; | |
69 }; | |
70 auto has_ex_style = [&window_ex_style](DWORD ex_style) { | |
71 return (window_ex_style & ex_style) != 0; | |
72 }; | |
73 | |
74 // Toolbars, tooltips and similar topmost windows | |
75 if (has_style(WS_POPUP) && has_ex_style(WS_EX_TOOLWINDOW)) | |
76 return false; | |
77 if (has_ex_style(WS_EX_TOPMOST) && has_ex_style(WS_EX_TOOLWINDOW)) | |
78 return false; | |
79 | |
80 return true; | |
81 } | |
82 | |
83 static bool VerifyClassName(const std::wstring& name) { | |
84 static const std::set<std::wstring> invalid_names = { | |
85 // System classes | |
86 L"#32770", // Dialog box | |
87 L"CabinetWClass", // Windows Explorer | |
88 L"ComboLBox", | |
89 L"DDEMLEvent", | |
90 L"DDEMLMom", | |
91 L"DirectUIHWND", | |
92 L"GDI+ Hook Window Class", | |
93 L"IME", | |
94 L"Internet Explorer_Hidden", | |
95 L"MSCTFIME UI", | |
96 L"tooltips_class32", | |
97 }; | |
98 | |
99 return !name.empty() && !invalid_names.count(name); | |
100 } | |
101 | |
102 static bool VerifyProcessPath(const std::wstring& path) { | |
103 return !path.empty() && !IsSystemDirectory(path); | |
104 } | |
105 | |
106 static bool VerifyProcessFileName(const std::wstring& name) { | |
107 static const std::set<std::wstring> invalid_names = { | |
108 // System files | |
109 L"explorer", // Windows Explorer | |
110 L"taskeng", // Task Scheduler Engine | |
111 L"taskhost", // Host Process for Windows Tasks | |
112 L"taskhostex", // Host Process for Windows Tasks | |
113 L"Taskmgr", // Task Manager | |
114 }; | |
115 | |
116 return !name.empty() && !invalid_names.count(name); | |
117 } | |
118 | |
119 //////////////////////////////////////////////////////////////////////////////// | |
120 | |
121 static BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM param) { | |
122 if (!::IsWindowVisible(hwnd)) | |
123 return TRUE; | |
124 | |
125 if (!VerifyWindowStyle(hwnd)) | |
126 return TRUE; | |
127 | |
128 Window window; | |
129 window.id = static_cast<unsigned int>(reinterpret_cast<ULONG_PTR>(hwnd)); | |
130 window.text = ToUtf8String(GetWindowText(hwnd)); | |
131 | |
132 { | |
133 std::wstring class_name = GetWindowClassName(hwnd); | |
134 window.class_name = ToUtf8String(class_name); | |
135 if (!VerifyClassName(class_name)) | |
136 return TRUE; | |
137 } | |
138 | |
139 Process process; | |
140 process.pid = GetWindowProcessId(hwnd); | |
141 | |
142 const auto path = GetProcessPath(process.pid); | |
143 if (!VerifyProcessPath(path)) | |
144 return TRUE; | |
145 | |
146 { | |
147 std::wstring name = GetFileNameWithoutExtension(GetFileNameFromPath(path)); | |
148 process.name = ToUtf8String(name); | |
149 if (!VerifyProcessFileName(name)) | |
150 return TRUE; | |
151 } | |
152 | |
153 auto& window_proc = *reinterpret_cast<window_proc_t*>(param); | |
154 if (!window_proc(process, window)) | |
155 return FALSE; | |
156 | |
157 return TRUE; | |
158 } | |
159 | |
160 bool Win32WinTools::EnumerateWindows(window_proc_t window_proc) { | |
161 if (!window_proc) | |
162 return false; | |
163 | |
164 const auto param = reinterpret_cast<LPARAM>(&window_proc); | |
165 | |
166 // Note that EnumWindows enumerates only top-level windows of desktop apps | |
167 // (as opposed to UWP apps) on Windows 8 and above. | |
168 return ::EnumWindows(EnumWindowsProc, param) != FALSE; | |
169 } | |
170 | |
171 } // namespace animia::win::detail |