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