Module: wine Branch: master Commit: 317d113af7afcc2ff1c9889b831b0cbeb54bd5bc URL: https://gitlab.winehq.org/wine/wine/-/commit/317d113af7afcc2ff1c9889b831b0cb...
Author: Connor McAdams cmcadams@codeweavers.com Date: Mon Jun 26 13:43:01 2023 -0400
uiautomationcore: Add support for invoking serverside event callbacks.
Signed-off-by: Connor McAdams cmcadams@codeweavers.com
---
dlls/uiautomationcore/tests/uiautomation.c | 12 +-- dlls/uiautomationcore/uia_event.c | 114 +++++++++++++++++++++++------ 2 files changed, 97 insertions(+), 29 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 788eb1a4eba..4845fe7ab33 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -13974,8 +13974,8 @@ static void test_UiaAddEvent_client_proc(void) SET_EXPECT(prov_callback_proxy); SET_EXPECT(uia_event_callback); post_event_message(hwnd, WM_UIA_TEST_RAISE_EVENT, HandleToUlong(hwnd), PROVIDER_ID, ProviderOptions_ServerSideProvider); - todo_wine ok(!WaitForSingleObject(EventData.event_handle, 2000), "Wait for event_handle failed.\n"); - todo_wine CHECK_CALLED(uia_event_callback); + ok(!WaitForSingleObject(EventData.event_handle, 2000), "Wait for event_handle failed.\n"); + CHECK_CALLED(uia_event_callback); CHECK_CALLED(prov_callback_base_hwnd); CHECK_CALLED(prov_callback_nonclient); todo_wine CHECK_CALLED(prov_callback_proxy); @@ -13995,8 +13995,8 @@ static void test_UiaAddEvent_client_proc(void)
SET_EXPECT(uia_event_callback); post_event_message(hwnd, WM_UIA_TEST_RAISE_EVENT, 0, PROVIDER2_ID, ProviderOptions_ServerSideProvider); - todo_wine ok(!WaitForSingleObject(EventData.event_handle, 2000), "Wait for event_handle failed.\n"); - todo_wine CHECK_CALLED(uia_event_callback); + ok(!WaitForSingleObject(EventData.event_handle, 2000), "Wait for event_handle failed.\n"); + CHECK_CALLED(uia_event_callback);
hr = UiaRemoveEvent(event); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -14109,8 +14109,8 @@ static void test_UiaAddEvent_client_proc(void) set_event_data(0, 0, 1, 1, &exp_node_desc, L"P)"); SET_EXPECT(uia_event_callback); post_event_message(hwnd, WM_UIA_TEST_RAISE_EVENT_RT_ID, 0xbeef, PROVIDER2_ID, 0x1337); - todo_wine ok(!WaitForSingleObject(EventData.event_handle, 2000), "Wait for event_handle failed.\n"); - todo_wine CHECK_CALLED(uia_event_callback); + ok(!WaitForSingleObject(EventData.event_handle, 2000), "Wait for event_handle failed.\n"); + CHECK_CALLED(uia_event_callback);
hr = UiaRemoveEvent(event); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); diff --git a/dlls/uiautomationcore/uia_event.c b/dlls/uiautomationcore/uia_event.c index a77fe3dd30f..be3e422c313 100644 --- a/dlls/uiautomationcore/uia_event.c +++ b/dlls/uiautomationcore/uia_event.c @@ -267,13 +267,26 @@ static CRITICAL_SECTION_DEBUG event_thread_cs_debug = }; static CRITICAL_SECTION event_thread_cs = { &event_thread_cs_debug, -1, 0, 0, 0, 0 };
+enum uia_queue_event_type { + QUEUE_EVENT_TYPE_SERVERSIDE, + QUEUE_EVENT_TYPE_CLIENTSIDE, +}; + struct uia_queue_event { struct list event_queue_entry; + int queue_event_type;
struct uia_event_args *args; struct uia_event *event; - HUIANODE node; + union { + struct { + HUIANODE node; + } serverside; + struct { + LRESULT node; + } clientside; + } u; };
static void uia_event_queue_push(struct uia_queue_event *event) @@ -303,31 +316,73 @@ static struct uia_queue_event *uia_event_queue_pop(struct list *event_queue) return queue_event; }
+static HRESULT uia_event_invoke(HUIANODE node, struct uia_event_args *args, struct uia_event *event); +static HRESULT uia_raise_clientside_event(struct uia_queue_event *event) +{ + HUIANODE node; + HRESULT hr; + + hr = uia_node_from_lresult(event->u.clientside.node, &node); + if (SUCCEEDED(hr)) + { + hr = uia_event_invoke(node, event->args, event->event); + UiaNodeRelease(node); + } + + return hr; +} + +static HRESULT uia_raise_serverside_event(struct uia_queue_event *event) +{ + HRESULT hr = S_OK; + LRESULT lr; + + /* + * uia_lresult_from_node is expected to release the node here upon + * failure. + */ + if ((lr = uia_lresult_from_node(event->u.serverside.node))) + { + VARIANT v; + + V_VT(&v) = VT_I4; + V_I4(&v) = lr; + hr = IWineUiaEvent_raise_event(event->event->u.serverside.event_iface, v); + if (FAILED(hr)) + { + IWineUiaNode *node; + + /* + * If the method returned failure, make sure we don't leave a + * dangling IWineUiaNode. + */ + if (SUCCEEDED(ObjectFromLresult(lr, &IID_IWineUiaNode, 0, (void **)&node))) + IWineUiaNode_Release(node); + } + } + else + hr = E_FAIL; + + return hr; +} + static void uia_event_thread_process_queue(struct list *event_queue) { while (1) { struct uia_queue_event *event; - LRESULT lr; HRESULT hr;
if (!(event = uia_event_queue_pop(event_queue))) break;
- /* - * uia_lresult_from_node is expected to release the node here upon - * failure. - */ - if ((lr = uia_lresult_from_node(event->node))) - { - VARIANT v; + if (event->queue_event_type == QUEUE_EVENT_TYPE_SERVERSIDE) + hr = uia_raise_serverside_event(event); + else + hr = uia_raise_clientside_event(event);
- V_VT(&v) = VT_I4; - V_I4(&v) = lr; - hr = IWineUiaEvent_raise_event(event->event->u.serverside.event_iface, v); - if (FAILED(hr)) - WARN("IWineUiaEvent_raise_event failed with hr %#lx\n", hr); - } + 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); @@ -583,18 +638,30 @@ static HRESULT WINAPI uia_event_set_event_data(IWineUiaEvent *iface, const GUID static HRESULT WINAPI uia_event_raise_event(IWineUiaEvent *iface, VARIANT in_node) { struct uia_event *event = impl_from_IWineUiaEvent(iface); - HUIANODE node; - HRESULT hr; + struct uia_queue_event *queue_event; + struct uia_event_args *args;
- FIXME("%p, %s: stub\n", iface, debugstr_variant(&in_node)); + TRACE("%p, %s\n", iface, debugstr_variant(&in_node));
assert(event->event_type != EVENT_TYPE_SERVERSIDE);
- hr = uia_node_from_lresult((LRESULT)V_I4(&in_node), &node); - if (FAILED(hr)) - return hr; + if (!(queue_event = heap_alloc_zero(sizeof(*queue_event)))) + return E_OUTOFMEMORY; + + if (!(args = create_uia_event_args(uia_event_info_from_id(event->event_id)))) + { + heap_free(queue_event); + 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); + + IWineUiaEvent_AddRef(&event->IWineUiaEvent_iface); + uia_event_queue_push(queue_event);
- UiaNodeRelease(node); return S_OK; }
@@ -1159,9 +1226,10 @@ static HRESULT uia_event_invoke(HUIANODE node, struct uia_event_args *args, stru return hr; }
+ queue_event->queue_event_type = QUEUE_EVENT_TYPE_SERVERSIDE; queue_event->args = args; queue_event->event = event; - queue_event->node = node2; + queue_event->u.serverside.node = node2;
InterlockedIncrement(&args->ref); IWineUiaEvent_AddRef(&event->IWineUiaEvent_iface);