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 |
