Mercurial > minori
annotate dep/animone/src/win/win32.cc @ 277:a796e97cc86d
dep/animone: x11: correctly check for connection failure
if there's no X server running then the previous code segfaults(!)
| author | Paper <paper@paper.us.eu.org> |
|---|---|
| date | Mon, 22 Apr 2024 19:11:06 -0400 |
| parents | 09c5bd74fe93 |
| children | b1f625b0227c |
| rev | line source |
|---|---|
| 258 | 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" | |
|
267
09c5bd74fe93
win32: make builds work again
Paper <paper@paper.us.eu.org>
parents:
258
diff
changeset
|
12 #include "animone/fd.h" |
| 258 | 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); | |
|
267
09c5bd74fe93
win32: make builds work again
Paper <paper@paper.us.eu.org>
parents:
258
diff
changeset
|
124 GetProcessName(process.pid, process.name); |
| 258 | 125 |
|
267
09c5bd74fe93
win32: make builds work again
Paper <paper@paper.us.eu.org>
parents:
258
diff
changeset
|
126 auto& window_proc = *reinterpret_cast<window_proc_t*>(param); |
| 258 | 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 |
