From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/uia_classes.idl | 2 +- dlls/uiautomationcore/uia_client.c | 22 ++++--- dlls/uiautomationcore/uia_event.c | 88 +++++++++++++++++++++++---- dlls/uiautomationcore/uia_private.h | 7 ++- dlls/uiautomationcore/uia_provider.c | 1 - 5 files changed, 98 insertions(+), 22 deletions(-)
diff --git a/dlls/uiautomationcore/uia_classes.idl b/dlls/uiautomationcore/uia_classes.idl index 3f8e17d3d72..74ea1b1a244 100644 --- a/dlls/uiautomationcore/uia_classes.idl +++ b/dlls/uiautomationcore/uia_classes.idl @@ -103,6 +103,6 @@ library UIA_wine_private HRESULT get_prop_val([in]const GUID *prop_guid, [out, retval]VARIANT *ret_val); HRESULT disconnect(); HRESULT get_hwnd([out, retval]ULONG *out_hwnd); - HRESULT attach_event([out, retval]IWineUiaEvent **ret_event); + HRESULT attach_event([in]long proc_id, [in]long event_cookie, [out, retval]IWineUiaEvent **ret_event); } } diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 5fe548bff18..6d468b68705 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -539,23 +539,29 @@ static HRESULT WINAPI uia_node_get_hwnd(IWineUiaNode *iface, ULONG *out_hwnd) return S_OK; }
-static HRESULT WINAPI uia_node_attach_event(IWineUiaNode *iface, IWineUiaEvent **ret_event) +static HRESULT WINAPI uia_node_attach_event(IWineUiaNode *iface, long proc_id, long event_cookie, + IWineUiaEvent **ret_event) { struct uia_node *node = impl_from_IWineUiaNode(iface); struct uia_event *event = NULL; HRESULT hr;
- TRACE("%p, %p\n", node, ret_event); + TRACE("%p, %ld, %ld, %p\n", node, proc_id, event_cookie, ret_event);
*ret_event = NULL; - hr = create_serverside_uia_event(&event); + hr = create_serverside_uia_event(&event, proc_id, event_cookie); if (FAILED(hr)) return hr;
+ /* Newly created serverside event. */ + if (hr == S_OK) + *ret_event = &event->IWineUiaEvent_iface; + hr = attach_event_to_node_provider(iface, 0, (HUIAEVENT)event); if (FAILED(hr)) { IWineUiaEvent_Release(&event->IWineUiaEvent_iface); + *ret_event = NULL; return hr; }
@@ -563,9 +569,11 @@ static HRESULT WINAPI uia_node_attach_event(IWineUiaNode *iface, IWineUiaEvent * * Attach this nested node to the serverside event to keep the provider * thread alive. */ - IWineUiaNode_AddRef(iface); - event->u.serverside.node = iface; - *ret_event = &event->IWineUiaEvent_iface; + if (*ret_event) + { + IWineUiaNode_AddRef(iface); + event->u.serverside.node = iface; + }
return hr; } @@ -2282,7 +2290,7 @@ static HRESULT WINAPI uia_nested_node_provider_attach_event(IWineUiaProvider *if
TRACE("%p, %#Ix\n", iface, huiaevent);
- hr = IWineUiaNode_attach_event(prov->nested_node, &remote_event); + hr = IWineUiaNode_attach_event(prov->nested_node, GetCurrentProcessId(), event->event_cookie, &remote_event); if (FAILED(hr) || !remote_event) return hr;
diff --git a/dlls/uiautomationcore/uia_event.c b/dlls/uiautomationcore/uia_event.c index 4822b74f6e9..d619ebe15cb 100644 --- a/dlls/uiautomationcore/uia_event.c +++ b/dlls/uiautomationcore/uia_event.c @@ -57,6 +57,10 @@ static struct uia_event_map { struct rb_tree event_map; LONG event_count; + + /* rb_tree for serverside events, sorted by PID/event cookie. */ + struct rb_tree serverside_event_map; + LONG serverside_event_count; } uia_event_map;
struct uia_event_map_entry @@ -77,6 +81,22 @@ struct uia_event_map_entry struct list events_list; };
+struct uia_event_identifier { + LONG event_cookie; + LONG proc_id; +}; + +static int uia_serverside_event_id_compare(const void *key, const struct rb_entry *entry) +{ + struct uia_event *event = RB_ENTRY_VALUE(entry, struct uia_event, u.serverside.serverside_event_entry); + struct uia_event_identifier *event_id = (struct uia_event_identifier *)key; + + if (event_id->proc_id != event->u.serverside.proc_id) + return (event_id->proc_id > event->u.serverside.proc_id) - (event_id->proc_id < event->u.serverside.proc_id); + else + return (event_id->event_cookie > event->event_cookie) - (event_id->event_cookie < event->event_cookie); +} + static CRITICAL_SECTION event_map_cs; static CRITICAL_SECTION_DEBUG event_map_cs_debug = { @@ -232,7 +252,13 @@ static ULONG WINAPI uia_event_Release(IWineUiaEvent *iface) CoDecrementMTAUsage(event->u.clientside.mta_cookie); } else + { + EnterCriticalSection(&event_map_cs); + rb_remove(&uia_event_map.serverside_event_map, &event->u.serverside.serverside_event_entry); + uia_event_map.serverside_event_count--; + LeaveCriticalSection(&event_map_cs); IWineUiaNode_Release(event->u.serverside.node); + }
for (i = 0; i < event->event_advisers_count; i++) IWineUiaEventAdviser_Release(event->event_advisers[i]); @@ -292,8 +318,7 @@ static struct uia_event *unsafe_impl_from_IWineUiaEvent(IWineUiaEvent *iface) return CONTAINING_RECORD(iface, struct uia_event, IWineUiaEvent_iface); }
-static HRESULT create_uia_event(struct uia_event **out_event, int event_id, int scope, UiaEventCallback *cback, - SAFEARRAY *runtime_id) +static HRESULT create_uia_event(struct uia_event **out_event, LONG event_cookie, int event_type) { struct uia_event *event = heap_alloc_zero(sizeof(*event));
@@ -303,30 +328,69 @@ static HRESULT create_uia_event(struct uia_event **out_event, int event_id, int
event->IWineUiaEvent_iface.lpVtbl = &uia_event_vtbl; event->ref = 1; + event->event_cookie = event_cookie; + event->event_type = event_type; + *out_event = event; + + return S_OK; +} + +static HRESULT create_clientside_uia_event(struct uia_event **out_event, int event_id, int scope, UiaEventCallback *cback, + SAFEARRAY *runtime_id) +{ + struct uia_event *event = NULL; + static LONG next_event_cookie; + HRESULT hr; + + *out_event = NULL; + hr = create_uia_event(&event, next_event_cookie, EVENT_TYPE_CLIENTSIDE); + if (FAILED(hr)) + return hr; + + InterlockedIncrement(&next_event_cookie); event->runtime_id = runtime_id; event->event_id = event_id; event->scope = scope; event->u.clientside.cback = cback; - event->event_type = EVENT_TYPE_CLIENTSIDE;
*out_event = event; return S_OK; }
-HRESULT create_serverside_uia_event(struct uia_event **out_event) +HRESULT create_serverside_uia_event(struct uia_event **out_event, LONG process_id, LONG event_cookie) { - struct uia_event *event = heap_alloc_zero(sizeof(*event)); + struct uia_event_identifier event_identifier = { event_cookie, process_id }; + struct rb_entry *rb_entry; + struct uia_event *event; + HRESULT hr = S_OK;
+ /* + * Attempt to lookup an existing event for this PID/event_cookie. If there + * is one, return S_FALSE. + */ *out_event = NULL; - if (!event) - return E_OUTOFMEMORY; + EnterCriticalSection(&event_map_cs); + if (uia_event_map.serverside_event_count && (rb_entry = rb_get(&uia_event_map.serverside_event_map, &event_identifier))) + { + *out_event = RB_ENTRY_VALUE(rb_entry, struct uia_event, u.serverside.serverside_event_entry); + hr = S_FALSE; + goto exit; + }
- event->IWineUiaEvent_iface.lpVtbl = &uia_event_vtbl; - event->ref = 1; - event->event_type = EVENT_TYPE_SERVERSIDE; + hr = create_uia_event(&event, event_cookie, EVENT_TYPE_SERVERSIDE); + if (FAILED(hr)) + goto exit;
+ event->u.serverside.proc_id = process_id; + uia_event_map.serverside_event_count++; + if (uia_event_map.serverside_event_count == 1) + rb_init(&uia_event_map.serverside_event_map, uia_serverside_event_id_compare); + rb_put(&uia_event_map.serverside_event_map, &event_identifier, &event->u.serverside.serverside_event_entry); *out_event = event; - return S_OK; + +exit: + LeaveCriticalSection(&event_map_cs); + return hr; }
static HRESULT uia_event_add_event_adviser(IWineUiaEventAdviser *adviser, struct uia_event *event) @@ -610,7 +674,7 @@ HRESULT WINAPI UiaAddEvent(HUIANODE huianode, EVENTID event_id, UiaEventCallback if (FAILED(hr)) return hr;
- hr = create_uia_event(&event, event_id, scope, callback, sa); + hr = create_clientside_uia_event(&event, event_id, scope, callback, sa); if (FAILED(hr)) { SafeArrayDestroy(sa); diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h index 4bd9281d486..c4f8f46abb0 100644 --- a/dlls/uiautomationcore/uia_private.h +++ b/dlls/uiautomationcore/uia_private.h @@ -21,6 +21,7 @@ #include "uiautomation.h" #include "uia_classes.h" #include "wine/list.h" +#include "wine/rbtree.h" #include "wine/heap.h"
extern HMODULE huia_module DECLSPEC_HIDDEN; @@ -116,6 +117,7 @@ struct uia_event struct uia_event_map_entry *event_map_entry; LONG event_defunct;
+ LONG event_cookie; int event_type; union { @@ -137,6 +139,9 @@ struct uia_event * event thread. */ IWineUiaNode *node; + + struct rb_entry serverside_event_entry; + LONG proc_id; } serverside; } u; }; @@ -196,7 +201,7 @@ BOOL uia_condition_matched(HRESULT hr) DECLSPEC_HIDDEN; HRESULT create_uia_iface(IUnknown **iface, BOOL is_cui8) DECLSPEC_HIDDEN;
/* uia_event.c */ -HRESULT create_serverside_uia_event(struct uia_event **out_event) DECLSPEC_HIDDEN; +HRESULT create_serverside_uia_event(struct uia_event **out_event, LONG process_id, LONG event_cookie) DECLSPEC_HIDDEN; 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; diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c index a00e9312ff7..faa7e2cb7fa 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -20,7 +20,6 @@ #include "ocidl.h"
#include "wine/debug.h" -#include "wine/rbtree.h" #include "initguid.h" #include "wine/iaccessible2.h"