Module: wine Branch: master Commit: 2a2c4cd7b984be5db239a7ea930ede59207560cf URL: https://gitlab.winehq.org/wine/wine/-/commit/2a2c4cd7b984be5db239a7ea930ede5...
Author: Connor McAdams cmcadams@codeweavers.com Date: Wed Sep 13 12:48:10 2023 -0400
uiautomationcore: Add WinEvent hook on the UIA event thread.
Signed-off-by: Connor McAdams cmcadams@codeweavers.com
---
dlls/uiautomationcore/uia_event.c | 121 +++++++++++++++++++++++++++++++++----- 1 file changed, 105 insertions(+), 16 deletions(-)
diff --git a/dlls/uiautomationcore/uia_event.c b/dlls/uiautomationcore/uia_event.c index 10dc1934844..04067f39e0e 100644 --- a/dlls/uiautomationcore/uia_event.c +++ b/dlls/uiautomationcore/uia_event.c @@ -50,6 +50,20 @@ static SAFEARRAY *uia_get_desktop_rt_id(void) return uia_desktop_node_rt_id; }
+static int win_event_to_uia_event_id(int win_event) +{ + switch (win_event) + { + case EVENT_OBJECT_FOCUS: return UIA_AutomationFocusChangedEventId; + case EVENT_SYSTEM_ALERT: return UIA_SystemAlertEventId; + + default: + break; + } + + return 0; +} + /* * UI Automation event map. */ @@ -247,6 +261,7 @@ struct uia_event_thread LONG ref;
struct list *event_queue; + HWINEVENTHOOK hook; };
#define WM_UIA_EVENT_THREAD_STOP (WM_USER + 1) @@ -264,12 +279,18 @@ static CRITICAL_SECTION event_thread_cs = { &event_thread_cs_debug, -1, 0, 0, 0, enum uia_queue_event_type { QUEUE_EVENT_TYPE_SERVERSIDE, QUEUE_EVENT_TYPE_CLIENTSIDE, + QUEUE_EVENT_TYPE_WIN_EVENT, };
struct uia_queue_event { struct list event_queue_entry; int queue_event_type; +}; + +struct uia_queue_uia_event +{ + struct uia_queue_event queue_entry;
struct uia_event_args *args; struct uia_event *event; @@ -285,14 +306,40 @@ struct uia_queue_event } u; };
-static void uia_event_queue_push(struct uia_queue_event *event) +struct uia_queue_win_event +{ + struct uia_queue_event queue_entry; + + HWINEVENTHOOK hook; + DWORD event_id; + HWND hwnd; + LONG obj_id; + LONG child_id; + DWORD thread_id; + DWORD event_time; +}; + +static void uia_event_queue_push(struct uia_queue_event *event, int queue_event_type) { + event->queue_event_type = queue_event_type; EnterCriticalSection(&event_thread_cs);
+ if (queue_event_type == QUEUE_EVENT_TYPE_WIN_EVENT) + { + struct uia_queue_win_event *win_event = (struct uia_queue_win_event *)event; + + if (win_event->hook != event_thread.hook) + { + free(event); + goto exit; + } + } + assert(event_thread.event_queue); list_add_tail(event_thread.event_queue, &event->event_queue_entry); PostMessageW(event_thread.hwnd, WM_UIA_EVENT_THREAD_PROCESS_QUEUE, 0, 0);
+exit: LeaveCriticalSection(&event_thread_cs); }
@@ -322,7 +369,7 @@ static void uia_node_lresult_release(LRESULT lr)
static HRESULT uia_event_invoke(HUIANODE node, HUIANODE nav_start_node, struct uia_event_args *args, struct uia_event *event); -static HRESULT uia_raise_clientside_event(struct uia_queue_event *event) +static HRESULT uia_raise_clientside_event(struct uia_queue_uia_event *event) { HUIANODE node, nav_start_node; HRESULT hr; @@ -354,7 +401,7 @@ static HRESULT uia_raise_clientside_event(struct uia_queue_event *event) return hr; }
-static HRESULT uia_raise_serverside_event(struct uia_queue_event *event) +static HRESULT uia_raise_serverside_event(struct uia_queue_uia_event *event) { HRESULT hr = S_OK; LRESULT lr, lr2; @@ -397,29 +444,70 @@ static void uia_event_thread_process_queue(struct list *event_queue) while (1) { struct uia_queue_event *event; - HRESULT hr; + HRESULT hr = S_OK;
if (!(event = uia_event_queue_pop(event_queue))) break;
- if (event->queue_event_type == QUEUE_EVENT_TYPE_SERVERSIDE) - hr = uia_raise_serverside_event(event); - else - hr = uia_raise_clientside_event(event); + switch (event->queue_event_type) + { + case QUEUE_EVENT_TYPE_SERVERSIDE: + case QUEUE_EVENT_TYPE_CLIENTSIDE: + { + struct uia_queue_uia_event *uia_event = (struct uia_queue_uia_event *)event; + + if (event->queue_event_type == QUEUE_EVENT_TYPE_SERVERSIDE) + hr = uia_raise_serverside_event(uia_event); + else + hr = uia_raise_clientside_event(uia_event); + + uia_event_args_release(uia_event->args); + IWineUiaEvent_Release(&uia_event->event->IWineUiaEvent_iface); + break; + } + + default: + break; + }
if (FAILED(hr)) WARN("Failed to raise event type %d with hr %#lx\n", event->queue_event_type, hr);
- uia_event_args_release(event->args); - IWineUiaEvent_Release(&event->event->IWineUiaEvent_iface); free(event); } }
+static void CALLBACK uia_event_thread_win_event_proc(HWINEVENTHOOK hook, DWORD event_id, HWND hwnd, LONG obj_id, + LONG child_id, DWORD thread_id, DWORD event_time) +{ + struct uia_queue_win_event *win_event; + + TRACE("%p, %ld, %p, %ld, %ld, %ld, %ld\n", hook, event_id, hwnd, obj_id, child_id, thread_id, event_time); + + if (!win_event_to_uia_event_id(event_id)) + return; + + if (!(win_event = calloc(1, sizeof(*win_event)))) + { + ERR("Failed to allocate uia_queue_win_event structure\n"); + return; + } + + win_event->hook = hook; + win_event->event_id = event_id; + win_event->hwnd = hwnd; + win_event->obj_id = obj_id; + win_event->child_id = child_id; + win_event->thread_id = thread_id; + win_event->event_time = event_time; + uia_event_queue_push(&win_event->queue_entry, QUEUE_EVENT_TYPE_WIN_EVENT); +} + static DWORD WINAPI uia_event_thread_proc(void *arg) { HANDLE initialized_event = arg; struct list event_queue; + HWINEVENTHOOK hook; HWND hwnd; MSG msg;
@@ -435,6 +523,8 @@ static DWORD WINAPI uia_event_thread_proc(void *arg)
event_thread.hwnd = hwnd; event_thread.event_queue = &event_queue; + event_thread.hook = hook = SetWinEventHook(EVENT_MIN, EVENT_MAX, 0, uia_event_thread_win_event_proc, 0, 0, + WINEVENT_OUTOFCONTEXT);
/* Initialization complete, thread can now process window messages. */ SetEvent(initialized_event); @@ -455,6 +545,7 @@ static DWORD WINAPI uia_event_thread_proc(void *arg)
TRACE("Shutting down UI Automation event thread.\n");
+ UnhookWinEvent(hook); DestroyWindow(hwnd); CoUninitialize(); FreeLibraryAndExitThread(huia_module, 0); @@ -664,7 +755,7 @@ static HRESULT WINAPI uia_event_set_event_data(IWineUiaEvent *iface, const GUID static HRESULT WINAPI uia_event_raise_event(IWineUiaEvent *iface, VARIANT in_node, VARIANT in_nav_start_node) { struct uia_event *event = impl_from_IWineUiaEvent(iface); - struct uia_queue_event *queue_event; + struct uia_queue_uia_event *queue_event; struct uia_event_args *args;
TRACE("%p, %s, %s\n", iface, debugstr_variant(&in_node), debugstr_variant(&in_nav_start_node)); @@ -680,7 +771,6 @@ static HRESULT WINAPI uia_event_raise_event(IWineUiaEvent *iface, VARIANT in_nod return E_OUTOFMEMORY; }
- queue_event->queue_event_type = QUEUE_EVENT_TYPE_CLIENTSIDE; queue_event->args = args; queue_event->event = event; queue_event->u.clientside.node = V_I4(&in_node); @@ -688,7 +778,7 @@ static HRESULT WINAPI uia_event_raise_event(IWineUiaEvent *iface, VARIANT in_nod queue_event->u.clientside.nav_start_node = V_I4(&in_nav_start_node);
IWineUiaEvent_AddRef(&event->IWineUiaEvent_iface); - uia_event_queue_push(queue_event); + uia_event_queue_push(&queue_event->queue_entry, QUEUE_EVENT_TYPE_CLIENTSIDE);
return S_OK; } @@ -1277,7 +1367,7 @@ static HRESULT uia_event_invoke(HUIANODE node, HUIANODE nav_start_node, struct u } else { - struct uia_queue_event *queue_event; + struct uia_queue_uia_event *queue_event; HUIANODE node2, nav_start_node2;
if (!(queue_event = calloc(1, sizeof(*queue_event)))) @@ -1302,7 +1392,6 @@ static HRESULT uia_event_invoke(HUIANODE node, HUIANODE nav_start_node, struct u } }
- queue_event->queue_event_type = QUEUE_EVENT_TYPE_SERVERSIDE; queue_event->args = args; queue_event->event = event; queue_event->u.serverside.node = node2; @@ -1310,7 +1399,7 @@ static HRESULT uia_event_invoke(HUIANODE node, HUIANODE nav_start_node, struct u
InterlockedIncrement(&args->ref); IWineUiaEvent_AddRef(&event->IWineUiaEvent_iface); - uia_event_queue_push(queue_event); + uia_event_queue_push(&queue_event->queue_entry, QUEUE_EVENT_TYPE_SERVERSIDE); }
return hr;