mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-06 08:54:05 +00:00
uiautomationcore: Add support for matching serverside events through navigation.
Signed-off-by: Connor McAdams <cmcadams@codeweavers.com>
This commit is contained in:
parent
68d0c88b06
commit
2622745083
|
@ -14063,11 +14063,11 @@ static void test_UiaAddEvent_client_proc(void)
|
|||
SET_EXPECT(uia_event_callback);
|
||||
|
||||
post_event_message(hwnd, WM_UIA_TEST_RAISE_EVENT, 0, PROVIDER_CHILD_ID, ProviderOptions_ServerSideProvider);
|
||||
todo_wine ok(!WaitForSingleObject(EventData.event_handle, 2000), "Wait for event_handle failed.\n");
|
||||
todo_wine CHECK_CALLED(prov_callback_base_hwnd);
|
||||
todo_wine CHECK_CALLED_MULTI(prov_callback_nonclient, 2);
|
||||
ok(!WaitForSingleObject(EventData.event_handle, 2000), "Wait for event_handle failed.\n");
|
||||
CHECK_CALLED(prov_callback_base_hwnd);
|
||||
CHECK_CALLED_MULTI(prov_callback_nonclient, 2);
|
||||
todo_wine CHECK_CALLED_MULTI(prov_callback_proxy, 2);
|
||||
todo_wine CHECK_CALLED(uia_event_callback);
|
||||
CHECK_CALLED(uia_event_callback);
|
||||
|
||||
hr = UiaRemoveEvent(event);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
|
@ -14696,7 +14696,7 @@ static void test_UiaAddEvent(const char *name)
|
|||
}
|
||||
}
|
||||
|
||||
todo_wine CHECK_CALLED_AT_LEAST(winproc_GETOBJECT_UiaRoot, 5);
|
||||
CHECK_CALLED_AT_LEAST(winproc_GETOBJECT_UiaRoot, 5);
|
||||
GetExitCodeProcess(proc.hProcess, &exit_code);
|
||||
if (exit_code > 255)
|
||||
ok(0, "unhandled exception %08x in child process %04x\n", (UINT)exit_code, (UINT)GetProcessId(proc.hProcess));
|
||||
|
|
|
@ -75,7 +75,7 @@ library UIA_wine_private
|
|||
HRESULT advise_events([in]BOOL advise_added, [in]long adviser_start_idx);
|
||||
HRESULT set_event_data([in]const GUID *event_guid, [in]long scope, [in]VARIANT runtime_id,
|
||||
[in]IWineUiaEvent *event_iface);
|
||||
HRESULT raise_event([in]VARIANT in_node);
|
||||
HRESULT raise_event([in]VARIANT in_node, [in]VARIANT in_nav_start_node);
|
||||
}
|
||||
|
||||
[
|
||||
|
|
|
@ -282,9 +282,11 @@ struct uia_queue_event
|
|||
union {
|
||||
struct {
|
||||
HUIANODE node;
|
||||
HUIANODE nav_start_node;
|
||||
} serverside;
|
||||
struct {
|
||||
LRESULT node;
|
||||
LRESULT nav_start_node;
|
||||
} clientside;
|
||||
} u;
|
||||
};
|
||||
|
@ -316,52 +318,82 @@ 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 void uia_node_lresult_release(LRESULT lr)
|
||||
{
|
||||
IWineUiaNode *node;
|
||||
|
||||
if (lr && SUCCEEDED(ObjectFromLresult(lr, &IID_IWineUiaNode, 0, (void **)&node)))
|
||||
IWineUiaNode_Release(node);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
HUIANODE node;
|
||||
HUIANODE node, nav_start_node;
|
||||
HRESULT hr;
|
||||
|
||||
node = nav_start_node = NULL;
|
||||
hr = uia_node_from_lresult(event->u.clientside.node, &node);
|
||||
if (SUCCEEDED(hr))
|
||||
if (FAILED(hr))
|
||||
{
|
||||
hr = uia_event_invoke(node, event->args, event->event);
|
||||
UiaNodeRelease(node);
|
||||
WARN("Failed to create node from lresult, hr %#lx\n", hr);
|
||||
uia_node_lresult_release(event->u.clientside.nav_start_node);
|
||||
return hr;
|
||||
}
|
||||
|
||||
if (event->u.clientside.nav_start_node)
|
||||
{
|
||||
hr = uia_node_from_lresult(event->u.clientside.nav_start_node, &nav_start_node);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WARN("Failed to create nav_start_node from lresult, hr %#lx\n", hr);
|
||||
UiaNodeRelease(node);
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
hr = uia_event_invoke(node, nav_start_node, event->args, event->event);
|
||||
UiaNodeRelease(node);
|
||||
UiaNodeRelease(nav_start_node);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT uia_raise_serverside_event(struct uia_queue_event *event)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
LRESULT lr;
|
||||
LRESULT lr, lr2;
|
||||
VARIANT v, v2;
|
||||
|
||||
/*
|
||||
* uia_lresult_from_node is expected to release the node here upon
|
||||
* failure.
|
||||
*/
|
||||
if ((lr = uia_lresult_from_node(event->u.serverside.node)))
|
||||
lr = lr2 = 0;
|
||||
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);
|
||||
}
|
||||
UiaNodeRelease(event->u.serverside.nav_start_node);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
if (event->u.serverside.nav_start_node && !(lr2 = uia_lresult_from_node(event->u.serverside.nav_start_node)))
|
||||
{
|
||||
uia_node_lresult_release(lr);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
VariantInit(&v2);
|
||||
variant_init_i4(&v, lr);
|
||||
if (lr2)
|
||||
variant_init_i4(&v2, lr2);
|
||||
|
||||
hr = IWineUiaEvent_raise_event(event->event->u.serverside.event_iface, v, v2);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
uia_node_lresult_release(lr);
|
||||
uia_node_lresult_release(lr2);
|
||||
}
|
||||
else
|
||||
hr = E_FAIL;
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
@ -635,13 +667,13 @@ static HRESULT WINAPI uia_event_set_event_data(IWineUiaEvent *iface, const GUID
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI uia_event_raise_event(IWineUiaEvent *iface, VARIANT in_node)
|
||||
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_event_args *args;
|
||||
|
||||
TRACE("%p, %s\n", iface, debugstr_variant(&in_node));
|
||||
TRACE("%p, %s, %s\n", iface, debugstr_variant(&in_node), debugstr_variant(&in_nav_start_node));
|
||||
|
||||
assert(event->event_type != EVENT_TYPE_SERVERSIDE);
|
||||
|
||||
|
@ -658,6 +690,8 @@ static HRESULT WINAPI uia_event_raise_event(IWineUiaEvent *iface, VARIANT in_nod
|
|||
queue_event->args = args;
|
||||
queue_event->event = event;
|
||||
queue_event->u.clientside.node = V_I4(&in_node);
|
||||
if (V_VT(&in_nav_start_node) == VT_I4)
|
||||
queue_event->u.clientside.nav_start_node = V_I4(&in_nav_start_node);
|
||||
|
||||
IWineUiaEvent_AddRef(&event->IWineUiaEvent_iface);
|
||||
uia_event_queue_push(queue_event);
|
||||
|
@ -1193,7 +1227,9 @@ HRESULT WINAPI UiaRemoveEvent(HUIAEVENT huiaevent)
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT uia_event_invoke(HUIANODE node, struct uia_event_args *args, struct uia_event *event)
|
||||
static HRESULT uia_event_check_match(HUIANODE node, HUIANODE nav_start_node, SAFEARRAY *rt_id,
|
||||
struct uia_event_args *args, struct uia_event *event);
|
||||
static HRESULT uia_event_invoke(HUIANODE node, HUIANODE nav_start_node, struct uia_event_args *args, struct uia_event *event)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
|
@ -1202,6 +1238,9 @@ static HRESULT uia_event_invoke(HUIANODE node, struct uia_event_args *args, stru
|
|||
SAFEARRAY *out_req;
|
||||
BSTR tree_struct;
|
||||
|
||||
if (nav_start_node)
|
||||
return uia_event_check_match(node, nav_start_node, NULL, args, event);
|
||||
|
||||
hr = UiaGetUpdatedCache(node, &event->u.clientside.cache_req, NormalizeState_View, NULL, &out_req,
|
||||
&tree_struct);
|
||||
if (SUCCEEDED(hr))
|
||||
|
@ -1214,11 +1253,12 @@ static HRESULT uia_event_invoke(HUIANODE node, struct uia_event_args *args, stru
|
|||
else
|
||||
{
|
||||
struct uia_queue_event *queue_event;
|
||||
HUIANODE node2;
|
||||
HUIANODE node2, nav_start_node2;
|
||||
|
||||
if (!(queue_event = heap_alloc_zero(sizeof(*queue_event))))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
node2 = nav_start_node2 = NULL;
|
||||
hr = clone_uia_node(node, &node2);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
|
@ -1226,10 +1266,22 @@ static HRESULT uia_event_invoke(HUIANODE node, struct uia_event_args *args, stru
|
|||
return hr;
|
||||
}
|
||||
|
||||
if (nav_start_node)
|
||||
{
|
||||
hr = clone_uia_node(nav_start_node, &nav_start_node2);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
heap_free(queue_event);
|
||||
UiaNodeRelease(node2);
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
queue_event->queue_event_type = QUEUE_EVENT_TYPE_SERVERSIDE;
|
||||
queue_event->args = args;
|
||||
queue_event->event = event;
|
||||
queue_event->u.serverside.node = node2;
|
||||
queue_event->u.serverside.nav_start_node = nav_start_node2;
|
||||
|
||||
InterlockedIncrement(&args->ref);
|
||||
IWineUiaEvent_AddRef(&event->IWineUiaEvent_iface);
|
||||
|
@ -1239,14 +1291,21 @@ static HRESULT uia_event_invoke(HUIANODE node, struct uia_event_args *args, stru
|
|||
return hr;
|
||||
}
|
||||
|
||||
static void set_refuse_hwnd_providers(struct uia_node *node, BOOL refuse_hwnd_providers)
|
||||
{
|
||||
struct uia_provider *prov_data = impl_from_IWineUiaProvider(node->prov[get_node_provider_type_at_idx(node, 0)]);
|
||||
|
||||
prov_data->refuse_hwnd_node_providers = refuse_hwnd_providers;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the provider that raised the event matches this particular event.
|
||||
*/
|
||||
static HRESULT uia_event_check_match(HUIANODE node, SAFEARRAY *rt_id, struct uia_event_args *args,
|
||||
struct uia_event *event)
|
||||
static HRESULT uia_event_check_match(HUIANODE node, HUIANODE nav_start_node, SAFEARRAY *rt_id,
|
||||
struct uia_event_args *args, struct uia_event *event)
|
||||
{
|
||||
struct UiaPropertyCondition prop_cond = { ConditionType_Property, UIA_RuntimeIdPropertyId };
|
||||
struct uia_node *node_data = impl_from_IWineUiaNode((IWineUiaNode *)node);
|
||||
struct uia_node *node_data = impl_from_IWineUiaNode((IWineUiaNode *)nav_start_node);
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
/* Event is no longer valid. */
|
||||
|
@ -1258,24 +1317,18 @@ static HRESULT uia_event_check_match(HUIANODE node, SAFEARRAY *rt_id, struct uia
|
|||
return S_OK;
|
||||
|
||||
if (event->desktop_subtree_event)
|
||||
return uia_event_invoke(node, args, event);
|
||||
return uia_event_invoke(node, NULL, args, event);
|
||||
|
||||
if (rt_id && !uia_compare_safearrays(rt_id, event->runtime_id, UIAutomationType_IntArray))
|
||||
{
|
||||
if (event->scope & TreeScope_Element)
|
||||
hr = uia_event_invoke(node, args, event);
|
||||
hr = uia_event_invoke(node, NULL, args, event);
|
||||
return hr;
|
||||
}
|
||||
|
||||
if (!(event->scope & (TreeScope_Descendants | TreeScope_Children)))
|
||||
return S_OK;
|
||||
|
||||
if (event->event_type == EVENT_TYPE_SERVERSIDE)
|
||||
{
|
||||
FIXME("Matching serverside events through navigation currently unimplemented\n");
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
V_VT(&prop_cond.Value) = VT_I4 | VT_ARRAY;
|
||||
V_ARRAY(&prop_cond.Value) = event->runtime_id;
|
||||
|
||||
|
@ -1284,6 +1337,22 @@ static HRESULT uia_event_check_match(HUIANODE node, SAFEARRAY *rt_id, struct uia
|
|||
{
|
||||
HUIANODE node2 = NULL;
|
||||
|
||||
/*
|
||||
* When trying to match serverside events through navigation, we
|
||||
* don't want any clientside providers added in the server process.
|
||||
* Once we encounter a provider with an HWND, we pass it off to the
|
||||
* client for any further navigation.
|
||||
*/
|
||||
if (event->event_type == EVENT_TYPE_SERVERSIDE)
|
||||
{
|
||||
if (node_data->hwnd)
|
||||
{
|
||||
hr = uia_event_invoke(node, (HUIANODE)&node_data->IWineUiaNode_iface, args, event);
|
||||
break;
|
||||
}
|
||||
set_refuse_hwnd_providers(node_data, TRUE);
|
||||
}
|
||||
|
||||
hr = navigate_uia_node(node_data, NavigateDirection_Parent, &node2);
|
||||
IWineUiaNode_Release(&node_data->IWineUiaNode_iface);
|
||||
if (FAILED(hr) || !node2)
|
||||
|
@ -1296,7 +1365,7 @@ static HRESULT uia_event_check_match(HUIANODE node, SAFEARRAY *rt_id, struct uia
|
|||
|
||||
if (uia_condition_matched(hr))
|
||||
{
|
||||
hr = uia_event_invoke(node, args, event);
|
||||
hr = uia_event_invoke(node, NULL, args, event);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1355,7 +1424,7 @@ static HRESULT uia_raise_event(IRawElementProviderSimple *elprov, struct uia_eve
|
|||
{
|
||||
struct uia_event *event = LIST_ENTRY(cursor, struct uia_event, event_list_entry);
|
||||
|
||||
hr = uia_event_check_match(node, sa, args, event);
|
||||
hr = uia_event_check_match(node, node, sa, args, event);
|
||||
if (FAILED(hr))
|
||||
break;
|
||||
}
|
||||
|
@ -1366,7 +1435,7 @@ static HRESULT uia_raise_event(IRawElementProviderSimple *elprov, struct uia_eve
|
|||
{
|
||||
struct uia_event *event = LIST_ENTRY(cursor, struct uia_event, event_list_entry);
|
||||
|
||||
hr = uia_event_check_match(node, sa, args, event);
|
||||
hr = uia_event_check_match(node, node, sa, args, event);
|
||||
if (FAILED(hr))
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue