Commit 2da4d47b authored by Connor McAdams's avatar Connor McAdams Committed by Alexandre Julliard

uiautomationcore: Prevent creation of duplicate serverside events.

parent 549a276c
...@@ -103,6 +103,6 @@ library UIA_wine_private ...@@ -103,6 +103,6 @@ library UIA_wine_private
HRESULT get_prop_val([in]const GUID *prop_guid, [out, retval]VARIANT *ret_val); HRESULT get_prop_val([in]const GUID *prop_guid, [out, retval]VARIANT *ret_val);
HRESULT disconnect(); HRESULT disconnect();
HRESULT get_hwnd([out, retval]ULONG *out_hwnd); 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);
} }
} }
...@@ -539,23 +539,29 @@ static HRESULT WINAPI uia_node_get_hwnd(IWineUiaNode *iface, ULONG *out_hwnd) ...@@ -539,23 +539,29 @@ static HRESULT WINAPI uia_node_get_hwnd(IWineUiaNode *iface, ULONG *out_hwnd)
return S_OK; 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_node *node = impl_from_IWineUiaNode(iface);
struct uia_event *event = NULL; struct uia_event *event = NULL;
HRESULT hr; 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; *ret_event = NULL;
hr = create_serverside_uia_event(&event); hr = create_serverside_uia_event(&event, proc_id, event_cookie);
if (FAILED(hr)) if (FAILED(hr))
return 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); hr = attach_event_to_node_provider(iface, 0, (HUIAEVENT)event);
if (FAILED(hr)) if (FAILED(hr))
{ {
IWineUiaEvent_Release(&event->IWineUiaEvent_iface); IWineUiaEvent_Release(&event->IWineUiaEvent_iface);
*ret_event = NULL;
return hr; return hr;
} }
...@@ -563,9 +569,11 @@ static HRESULT WINAPI uia_node_attach_event(IWineUiaNode *iface, IWineUiaEvent * ...@@ -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 * Attach this nested node to the serverside event to keep the provider
* thread alive. * thread alive.
*/ */
IWineUiaNode_AddRef(iface); if (*ret_event)
event->u.serverside.node = iface; {
*ret_event = &event->IWineUiaEvent_iface; IWineUiaNode_AddRef(iface);
event->u.serverside.node = iface;
}
return hr; return hr;
} }
...@@ -2282,7 +2290,7 @@ static HRESULT WINAPI uia_nested_node_provider_attach_event(IWineUiaProvider *if ...@@ -2282,7 +2290,7 @@ static HRESULT WINAPI uia_nested_node_provider_attach_event(IWineUiaProvider *if
TRACE("%p, %#Ix\n", iface, huiaevent); 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) if (FAILED(hr) || !remote_event)
return hr; return hr;
......
...@@ -57,6 +57,10 @@ static struct uia_event_map ...@@ -57,6 +57,10 @@ static struct uia_event_map
{ {
struct rb_tree event_map; struct rb_tree event_map;
LONG event_count; 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; } uia_event_map;
struct uia_event_map_entry struct uia_event_map_entry
...@@ -77,6 +81,22 @@ struct uia_event_map_entry ...@@ -77,6 +81,22 @@ struct uia_event_map_entry
struct list events_list; 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 event_map_cs;
static CRITICAL_SECTION_DEBUG event_map_cs_debug = static CRITICAL_SECTION_DEBUG event_map_cs_debug =
{ {
...@@ -231,8 +251,15 @@ static ULONG WINAPI uia_event_Release(IWineUiaEvent *iface) ...@@ -231,8 +251,15 @@ static ULONG WINAPI uia_event_Release(IWineUiaEvent *iface)
if (event->u.clientside.mta_cookie) if (event->u.clientside.mta_cookie)
CoDecrementMTAUsage(event->u.clientside.mta_cookie); CoDecrementMTAUsage(event->u.clientside.mta_cookie);
} }
else if (event->u.serverside.node) else
IWineUiaNode_Release(event->u.serverside.node); {
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);
if (event->u.serverside.node)
IWineUiaNode_Release(event->u.serverside.node);
}
for (i = 0; i < event->event_advisers_count; i++) for (i = 0; i < event->event_advisers_count; i++)
IWineUiaEventAdviser_Release(event->event_advisers[i]); IWineUiaEventAdviser_Release(event->event_advisers[i]);
...@@ -292,8 +319,7 @@ static struct uia_event *unsafe_impl_from_IWineUiaEvent(IWineUiaEvent *iface) ...@@ -292,8 +319,7 @@ static struct uia_event *unsafe_impl_from_IWineUiaEvent(IWineUiaEvent *iface)
return CONTAINING_RECORD(iface, struct uia_event, 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, static HRESULT create_uia_event(struct uia_event **out_event, LONG event_cookie, int event_type)
SAFEARRAY *runtime_id)
{ {
struct uia_event *event = heap_alloc_zero(sizeof(*event)); struct uia_event *event = heap_alloc_zero(sizeof(*event));
...@@ -303,30 +329,68 @@ static HRESULT create_uia_event(struct uia_event **out_event, int event_id, int ...@@ -303,30 +329,68 @@ static HRESULT create_uia_event(struct uia_event **out_event, int event_id, int
event->IWineUiaEvent_iface.lpVtbl = &uia_event_vtbl; event->IWineUiaEvent_iface.lpVtbl = &uia_event_vtbl;
event->ref = 1; 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, InterlockedIncrement(&next_event_cookie), EVENT_TYPE_CLIENTSIDE);
if (FAILED(hr))
return hr;
event->runtime_id = runtime_id; event->runtime_id = runtime_id;
event->event_id = event_id; event->event_id = event_id;
event->scope = scope; event->scope = scope;
event->u.clientside.cback = cback; event->u.clientside.cback = cback;
event->event_type = EVENT_TYPE_CLIENTSIDE;
*out_event = event; *out_event = event;
return S_OK; 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; *out_event = NULL;
if (!event) EnterCriticalSection(&event_map_cs);
return E_OUTOFMEMORY; 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; hr = create_uia_event(&event, event_cookie, EVENT_TYPE_SERVERSIDE);
event->ref = 1; if (FAILED(hr))
event->event_type = EVENT_TYPE_SERVERSIDE; 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; *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) static HRESULT uia_event_add_event_adviser(IWineUiaEventAdviser *adviser, struct uia_event *event)
...@@ -614,7 +678,7 @@ HRESULT WINAPI UiaAddEvent(HUIANODE huianode, EVENTID event_id, UiaEventCallback ...@@ -614,7 +678,7 @@ HRESULT WINAPI UiaAddEvent(HUIANODE huianode, EVENTID event_id, UiaEventCallback
if (FAILED(hr)) if (FAILED(hr))
return 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)) if (FAILED(hr))
{ {
SafeArrayDestroy(sa); SafeArrayDestroy(sa);
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "uiautomation.h" #include "uiautomation.h"
#include "uia_classes.h" #include "uia_classes.h"
#include "wine/list.h" #include "wine/list.h"
#include "wine/rbtree.h"
#include "wine/heap.h" #include "wine/heap.h"
extern HMODULE huia_module DECLSPEC_HIDDEN; extern HMODULE huia_module DECLSPEC_HIDDEN;
...@@ -116,6 +117,7 @@ struct uia_event ...@@ -116,6 +117,7 @@ struct uia_event
struct uia_event_map_entry *event_map_entry; struct uia_event_map_entry *event_map_entry;
LONG event_defunct; LONG event_defunct;
LONG event_cookie;
int event_type; int event_type;
union union
{ {
...@@ -137,6 +139,9 @@ struct uia_event ...@@ -137,6 +139,9 @@ struct uia_event
* event thread. * event thread.
*/ */
IWineUiaNode *node; IWineUiaNode *node;
struct rb_entry serverside_event_entry;
LONG proc_id;
} serverside; } serverside;
} u; } u;
}; };
...@@ -196,7 +201,7 @@ BOOL uia_condition_matched(HRESULT hr) DECLSPEC_HIDDEN; ...@@ -196,7 +201,7 @@ BOOL uia_condition_matched(HRESULT hr) DECLSPEC_HIDDEN;
HRESULT create_uia_iface(IUnknown **iface, BOOL is_cui8) DECLSPEC_HIDDEN; HRESULT create_uia_iface(IUnknown **iface, BOOL is_cui8) DECLSPEC_HIDDEN;
/* uia_event.c */ /* 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, HRESULT uia_event_add_provider_event_adviser(IRawElementProviderAdviseEvents *advise_events,
struct uia_event *event) DECLSPEC_HIDDEN; struct uia_event *event) DECLSPEC_HIDDEN;
HRESULT uia_event_add_serverside_event_adviser(IWineUiaEvent *serverside_event, struct uia_event *event) DECLSPEC_HIDDEN; HRESULT uia_event_add_serverside_event_adviser(IWineUiaEvent *serverside_event, struct uia_event *event) DECLSPEC_HIDDEN;
......
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
#include "ocidl.h" #include "ocidl.h"
#include "wine/debug.h" #include "wine/debug.h"
#include "wine/rbtree.h"
#include "initguid.h" #include "initguid.h"
#include "wine/iaccessible2.h" #include "wine/iaccessible2.h"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment