From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 8 +- dlls/uiautomationcore/uia_com_client.c | 113 +++++++++++++++++---- dlls/uiautomationcore/uia_event.c | 2 +- dlls/uiautomationcore/uia_private.h | 3 + 4 files changed, 99 insertions(+), 27 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 5bd8e52fddb..74bcd5c0e16 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -13132,8 +13132,8 @@ static DWORD WINAPI uia_com_event_handler_test_thread(LPVOID param) set_com_event_data(&exp_node_desc); hr = UiaRaiseAutomationEvent(&Provider2.IRawElementProviderSimple_iface, UIA_LiveRegionChangedEventId); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine CHECK_CALLED(uia_com_event_callback); - todo_wine ok(ComEventData.last_call_tid == GetCurrentThreadId(), "Event handler called on unexpected thread %ld\n", + CHECK_CALLED(uia_com_event_callback); + ok(ComEventData.last_call_tid == GetCurrentThreadId(), "Event handler called on unexpected thread %ld\n", ComEventData.last_call_tid); CoUninitialize();
@@ -13146,7 +13146,7 @@ static DWORD WINAPI uia_com_event_handler_test_thread(LPVOID param) set_com_event_data(&exp_node_desc); hr = UiaRaiseAutomationEvent(&Provider2.IRawElementProviderSimple_iface, UIA_LiveRegionChangedEventId); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine CHECK_CALLED(uia_com_event_callback); + CHECK_CALLED(uia_com_event_callback); ok(ComEventData.last_call_tid != GetCurrentThreadId(), "Event handler called on unexpected thread %ld\n", ComEventData.last_call_tid); CoUninitialize(); @@ -13233,7 +13233,7 @@ static void test_IUIAutomationEventHandler(IUIAutomation *uia_iface, IUIAutomati set_com_event_data(&exp_node_desc); hr = UiaRaiseAutomationEvent(&Provider2.IRawElementProviderSimple_iface, UIA_LiveRegionChangedEventId); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine CHECK_CALLED(uia_com_event_callback); + CHECK_CALLED(uia_com_event_callback);
/* * If no cache request is provided by the user in diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index 66326ad9574..b4545706238 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -950,26 +950,22 @@ static int uia_com_event_handler_id_compare(const void *key, const struct rb_ent }
struct uia_com_event { - IUnknown *handler_iface; + DWORD git_cookie; + HUIAEVENT event; + BOOL from_cui8;
struct list event_handler_map_list_entry; struct uia_event_handler_map_entry *handler_map; };
-static HRESULT uia_event_handlers_add_handler(IUnknown *handler_iface, SAFEARRAY *runtime_id, int event_id) +static HRESULT uia_event_handlers_add_handler(IUnknown *handler_iface, SAFEARRAY *runtime_id, int event_id, + struct uia_com_event *event) { struct uia_event_handler_identifier event_ident = { handler_iface, runtime_id, event_id }; struct uia_event_handler_map_entry *event_map; - struct uia_com_event *event; struct rb_entry *rb_entry; HRESULT hr = S_OK;
- if (!(event = heap_alloc_zero(sizeof(*event)))) - return E_OUTOFMEMORY; - - event->handler_iface = handler_iface; - IUnknown_AddRef(handler_iface); - EnterCriticalSection(&com_event_handlers_cs);
if (!com_event_handlers.handler_count) @@ -993,7 +989,7 @@ static HRESULT uia_event_handlers_add_handler(IUnknown *handler_iface, SAFEARRAY }
event_map->event_id = event_id; - event_map->handler_iface = event->handler_iface; + event_map->handler_iface = handler_iface; IUnknown_AddRef(event_map->handler_iface);
list_init(&event_map->handlers_list); @@ -1006,25 +1002,28 @@ static HRESULT uia_event_handlers_add_handler(IUnknown *handler_iface, SAFEARRAY
exit: LeaveCriticalSection(&com_event_handlers_cs); - if (FAILED(hr)) - { - IUnknown_Release(event->handler_iface); - heap_free(event); - }
return hr; }
+static void uia_event_handler_destroy(struct uia_com_event *event) +{ + list_remove(&event->event_handler_map_list_entry); + if (event->event) + UiaRemoveEvent(event->event); + if (event->git_cookie) + unregister_interface_in_git(event->git_cookie); + heap_free(event); +} + static void uia_event_handler_map_entry_destroy(struct uia_event_handler_map_entry *entry) { struct uia_com_event *event, *event2;
LIST_FOR_EACH_ENTRY_SAFE(event, event2, &entry->handlers_list, struct uia_com_event, event_handler_map_list_entry) { - list_remove(&event->event_handler_map_list_entry); - IUnknown_Release(event->handler_iface); + uia_event_handler_destroy(event); com_event_handlers.handler_count--; - heap_free(event); }
rb_remove(&com_event_handlers.handler_map, &entry->entry); @@ -1046,6 +1045,39 @@ static void uia_event_handlers_remove_handlers(IUnknown *handler_iface, SAFEARRA LeaveCriticalSection(&com_event_handlers_cs); }
+static HRESULT create_uia_element_from_cache_req(IUIAutomationElement **iface, BOOL from_cui8, + struct UiaCacheRequest *cache_req, LONG start_idx, SAFEARRAY *req_data, BSTR tree_struct); +static HRESULT uia_com_event_callback(struct uia_event *event, struct uia_event_args *args, + SAFEARRAY *cache_req, BSTR tree_struct) +{ + struct uia_com_event *com_event = (struct uia_com_event *)event->u.clientside.callback_data; + IUIAutomationEventHandler *handler; + IUIAutomationElement *elem; + BSTR tree_struct2; + HRESULT hr; + + /* Nothing matches the cache request view condition, do nothing. */ + if (!cache_req) + return S_OK; + + /* create_uia_element_from_cache_req frees the passed in BSTR. */ + tree_struct2 = SysAllocString(tree_struct); + hr = create_uia_element_from_cache_req(&elem, com_event->from_cui8, &event->u.clientside.cache_req, 0, cache_req, + tree_struct2); + if (FAILED(hr)) + return hr; + + hr = get_interface_in_git(&IID_IUIAutomationEventHandler, com_event->git_cookie, (IUnknown **)&handler); + if (SUCCEEDED(hr)) + { + hr = IUIAutomationEventHandler_HandleAutomationEvent(handler, elem, event->event_id); + IUIAutomationEventHandler_Release(handler); + } + IUIAutomationElement_Release(elem); + + return hr; +} + /* * IUIAutomationElementArray interface. */ @@ -1332,8 +1364,6 @@ static HRESULT set_find_params_struct(struct UiaFindParams *params, IUIAutomatio return S_OK; }
-static HRESULT create_uia_element_from_cache_req(IUIAutomationElement **iface, BOOL from_cui8, - struct UiaCacheRequest *cache_req, LONG start_idx, SAFEARRAY *req_data, BSTR tree_struct); static HRESULT WINAPI uia_element_FindFirstBuildCache(IUIAutomationElement9 *iface, enum TreeScope scope, IUIAutomationCondition *condition, IUIAutomationCacheRequest *cache_req, IUIAutomationElement **found) { @@ -3213,9 +3243,11 @@ static HRESULT WINAPI uia_iface_AddAutomationEventHandler(IUIAutomation6 *iface, IUIAutomationElement *elem, enum TreeScope scope, IUIAutomationCacheRequest *cache_req, IUIAutomationEventHandler *handler) { + struct UiaCacheRequest *cache_req_struct; + struct uia_com_event *com_event = NULL; + SAFEARRAY *runtime_id = NULL; struct uia_element *element; IUnknown *handler_iface; - SAFEARRAY *runtime_id; HRESULT hr;
TRACE("%p, %d, %p, %#x, %p, %p\n", iface, event_id, elem, scope, cache_req, handler); @@ -3232,12 +3264,49 @@ static HRESULT WINAPI uia_iface_AddAutomationEventHandler(IUIAutomation6 *iface,
element = impl_from_IUIAutomationElement9((IUIAutomationElement9 *)elem); hr = UiaGetRuntimeId(element->node, &runtime_id); + if (FAILED(hr)) + { + IUnknown_Release(handler_iface); + return hr; + } + + if (!cache_req) + { + hr = create_uia_cache_request_iface(&cache_req); + if (FAILED(hr)) + goto exit; + } + else + IUIAutomationCacheRequest_AddRef(cache_req); + + hr = get_uia_cache_request_struct_from_iface(cache_req, &cache_req_struct); + if (FAILED(hr)) + goto exit; + + if (!(com_event = heap_alloc_zero(sizeof(*com_event)))) + { + hr = E_OUTOFMEMORY; + goto exit; + } + + com_event->from_cui8 = element->from_cui8; + list_init(&com_event->event_handler_map_list_entry); + hr = register_interface_in_git((IUnknown *)handler, &IID_IUIAutomationEventHandler, &com_event->git_cookie); if (FAILED(hr)) goto exit;
- hr = uia_event_handlers_add_handler(handler_iface, runtime_id, event_id); + hr = uia_add_clientside_event(element->node, event_id, scope, NULL, 0, cache_req_struct, runtime_id, + uia_com_event_callback, (void *)com_event, &com_event->event); + if (FAILED(hr)) + goto exit; + + hr = uia_event_handlers_add_handler(handler_iface, runtime_id, event_id, com_event);
exit: + if (FAILED(hr) && com_event) + uia_event_handler_destroy(com_event); + if (cache_req) + IUIAutomationCacheRequest_Release(cache_req); IUnknown_Release(handler_iface); SafeArrayDestroy(runtime_id);
diff --git a/dlls/uiautomationcore/uia_event.c b/dlls/uiautomationcore/uia_event.c index 84120ae90fc..693b0b7509b 100644 --- a/dlls/uiautomationcore/uia_event.c +++ b/dlls/uiautomationcore/uia_event.c @@ -1140,7 +1140,7 @@ static HRESULT uia_clientside_event_callback(struct uia_event *event, struct uia return S_OK; }
-static HRESULT uia_add_clientside_event(HUIANODE huianode, EVENTID event_id, enum TreeScope scope, PROPERTYID *prop_ids, +HRESULT uia_add_clientside_event(HUIANODE huianode, EVENTID event_id, enum TreeScope scope, PROPERTYID *prop_ids, int prop_ids_count, struct UiaCacheRequest *cache_req, SAFEARRAY *rt_id, UiaWineEventCallback *cback, void *cback_data, HUIAEVENT *huiaevent) { diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h index 928b36fbae6..bbd2074a7f3 100644 --- a/dlls/uiautomationcore/uia_private.h +++ b/dlls/uiautomationcore/uia_private.h @@ -218,6 +218,9 @@ HRESULT create_serverside_uia_event(struct uia_event **out_event, LONG process_i HRESULT uia_event_add_provider_event_adviser(IRawElementProviderAdviseEvents *advise_events, struct uia_event *event) DECLSPEC_HIDDEN; HRESULT uia_event_add_serverside_event_adviser(IWineUiaEvent *serverside_event, struct uia_event *event) DECLSPEC_HIDDEN; +HRESULT uia_add_clientside_event(HUIANODE huianode, EVENTID event_id, enum TreeScope scope, PROPERTYID *prop_ids, + int prop_ids_count, struct UiaCacheRequest *cache_req, SAFEARRAY *rt_id, UiaWineEventCallback *cback, + void *cback_data, HUIAEVENT *huiaevent) DECLSPEC_HIDDEN;
/* uia_ids.c */ const struct uia_prop_info *uia_prop_info_from_id(PROPERTYID prop_id) DECLSPEC_HIDDEN;