Commit c5b2c036 authored by Connor McAdams's avatar Connor McAdams Committed by Alexandre Julliard

uiautomationcore: Implement UiaRaiseAutomationEvent.

parent 61712ec7
......@@ -13869,6 +13869,32 @@ static void test_UiaRemoveEvent_args(HUIANODE node)
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
}
static void test_UiaRaiseAutomationEvent_args(void)
{
HRESULT hr;
hr = UiaRaiseAutomationEvent(NULL, UIA_AutomationFocusChangedEventId);
ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
/* Returns failure code from get_ProviderOptions. */
initialize_provider(&Provider2, 0, NULL, TRUE);
hr = UiaRaiseAutomationEvent(&Provider2.IRawElementProviderSimple_iface, UIA_AutomationFocusChangedEventId);
/* Windows 7 returns S_OK. */
ok(hr == E_NOTIMPL || broken(hr == S_OK), "Unexpected hr %#lx.\n", hr);
/* Invalid event ID - doesn't return failure code. */
initialize_provider(&Provider2, ProviderOptions_ServerSideProvider, NULL, TRUE);
hr = UiaRaiseAutomationEvent(&Provider2.IRawElementProviderSimple_iface, 1);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
/*
* UIA_StructureChangedEventId should use UiaRaiseStructureChangedEvent.
* No failure code is returned, however.
*/
hr = UiaRaiseAutomationEvent(&Provider2.IRawElementProviderSimple_iface, UIA_StructureChangedEventId);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
}
static void test_UiaAddEvent(void)
{
IRawElementProviderFragmentRoot *embedded_roots[2] = { &Provider_child.IRawElementProviderFragmentRoot_iface,
......@@ -13908,6 +13934,7 @@ static void test_UiaAddEvent(void)
/* Test valid function input arguments. */
test_UiaAddEvent_args(node);
test_UiaRemoveEvent_args(node);
test_UiaRaiseAutomationEvent_args();
/*
* Raise event without any registered event handlers.
......@@ -13915,8 +13942,7 @@ static void test_UiaAddEvent(void)
method_sequences_enabled = TRUE;
hr = UiaRaiseAutomationEvent(&Provider.IRawElementProviderSimple_iface, UIA_AutomationFocusChangedEventId);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
if (SUCCEEDED(hr) && sequence_cnt)
ok_method_sequence(event_seq1, "event_seq1");
ok_method_sequence(event_seq1, "event_seq1");
/*
* Register an event on a node without an HWND/RuntimeId. The event will
......@@ -13941,8 +13967,7 @@ static void test_UiaAddEvent(void)
*/
hr = UiaRaiseAutomationEvent(&Provider.IRawElementProviderSimple_iface, UIA_AutomationFocusChangedEventId);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
if (SUCCEEDED(hr) && sequence_cnt)
ok_method_sequence(event_seq3, "event_seq3");
ok_method_sequence(event_seq3, "event_seq3");
hr = UiaRemoveEvent(event);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
......@@ -13976,7 +14001,7 @@ static void test_UiaAddEvent(void)
SET_EXPECT(uia_event_callback);
hr = UiaRaiseAutomationEvent(&Provider.IRawElementProviderSimple_iface, UIA_AutomationFocusChangedEventId);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
todo_wine CHECK_CALLED(uia_event_callback);
CHECK_CALLED(uia_event_callback);
/*
* Runtime ID matches so event callback is invoked, but nothing matches
......@@ -13991,7 +14016,7 @@ static void test_UiaAddEvent(void)
SET_EXPECT(uia_event_callback);
hr = UiaRaiseAutomationEvent(&Provider.IRawElementProviderSimple_iface, UIA_AutomationFocusChangedEventId);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
todo_wine CHECK_CALLED(uia_event_callback);
CHECK_CALLED(uia_event_callback);
set_provider_prop_override(&Provider, NULL, 0);
method_sequences_enabled = TRUE;
......@@ -14027,7 +14052,7 @@ static void test_UiaAddEvent(void)
SET_EXPECT(uia_event_callback);
hr = UiaRaiseAutomationEvent(&Provider_child.IRawElementProviderSimple_iface, UIA_AutomationFocusChangedEventId);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
todo_wine CHECK_CALLED(uia_event_callback);
CHECK_CALLED(uia_event_callback);
/* Provider_child doesn't match the view condition, but Provider does. */
variant_init_bool(&v, FALSE);
......@@ -14040,7 +14065,7 @@ static void test_UiaAddEvent(void)
SET_EXPECT(uia_event_callback);
hr = UiaRaiseAutomationEvent(&Provider_child.IRawElementProviderSimple_iface, UIA_AutomationFocusChangedEventId);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
todo_wine CHECK_CALLED(uia_event_callback);
CHECK_CALLED(uia_event_callback);
set_provider_prop_override(&Provider_child, NULL, 0);
hr = UiaRemoveEvent(event);
......@@ -14061,7 +14086,7 @@ static void test_UiaAddEvent(void)
SET_EXPECT(uia_event_callback);
hr = UiaRaiseAutomationEvent(&Provider_child_child.IRawElementProviderSimple_iface, UIA_AutomationFocusChangedEventId);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
todo_wine CHECK_CALLED(uia_event_callback);
CHECK_CALLED(uia_event_callback);
hr = UiaRemoveEvent(event);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
......@@ -14206,11 +14231,11 @@ static void test_UiaAddEvent(void)
Provider_hwnd2.prov_opts = ProviderOptions_ClientSideProvider;
hr = UiaRaiseAutomationEvent(&Provider_hwnd2.IRawElementProviderSimple_iface, UIA_AutomationFocusChangedEventId);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
todo_wine CHECK_CALLED(prov_callback_base_hwnd);
todo_wine CHECK_CALLED(prov_callback_nonclient);
CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
CHECK_CALLED(prov_callback_base_hwnd);
CHECK_CALLED(prov_callback_nonclient);
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);
......
......@@ -747,7 +747,7 @@ static HRESULT get_child_for_node(struct uia_node *node, int start_prov_idx, int
return S_OK;
}
static HRESULT navigate_uia_node(struct uia_node *node, int nav_dir, HUIANODE *out_node)
HRESULT navigate_uia_node(struct uia_node *node, int nav_dir, HUIANODE *out_node)
{
HRESULT hr;
VARIANT v;
......@@ -835,8 +835,6 @@ static HRESULT navigate_uia_node(struct uia_node *node, int nav_dir, HUIANODE *o
return S_OK;
}
static HRESULT uia_condition_check(HUIANODE node, struct UiaCondition *condition);
static BOOL uia_condition_matched(HRESULT hr);
static HRESULT conditional_navigate_uia_node(struct uia_node *node, int nav_dir, struct UiaCondition *cond,
HUIANODE *out_node)
{
......@@ -3024,7 +3022,7 @@ void WINAPI UiaRegisterProviderCallback(UiaProviderCallback *callback)
uia_provider_callback = default_uia_provider_callback;
}
static BOOL uia_condition_matched(HRESULT hr)
BOOL uia_condition_matched(HRESULT hr)
{
if (hr == S_FALSE)
return FALSE;
......@@ -3085,7 +3083,7 @@ static HRESULT uia_property_condition_check(HUIANODE node, struct UiaPropertyCon
return hr;
}
static HRESULT uia_condition_check(HUIANODE node, struct UiaCondition *condition)
HRESULT uia_condition_check(HUIANODE node, struct UiaCondition *condition)
{
HRESULT hr;
......
......@@ -503,3 +503,170 @@ HRESULT WINAPI UiaRemoveEvent(HUIAEVENT huiaevent)
return S_OK;
}
static HRESULT uia_event_invoke(HUIANODE node, struct UiaEventArgs *args, struct uia_event *event)
{
SAFEARRAY *out_req;
BSTR tree_struct;
HRESULT hr;
hr = UiaGetUpdatedCache(node, &event->cache_req, NormalizeState_View, NULL, &out_req,
&tree_struct);
if (SUCCEEDED(hr))
{
event->cback(args, out_req, tree_struct);
SafeArrayDestroy(out_req);
SysFreeString(tree_struct);
}
return hr;
}
/*
* Check if the provider that raised the event matches this particular event.
*/
static HRESULT uia_event_check_match(HUIANODE node, SAFEARRAY *rt_id, struct UiaEventArgs *args, struct uia_event *event)
{
struct UiaPropertyCondition prop_cond = { ConditionType_Property, UIA_RuntimeIdPropertyId };
struct uia_node *node_data = impl_from_IWineUiaNode((IWineUiaNode *)node);
HRESULT hr = S_OK;
/* Event is no longer valid. */
if (InterlockedCompareExchange(&event->event_defunct, 0, 0) != 0)
return S_OK;
/* Can't match an event that doesn't have a runtime ID, early out. */
if (!event->runtime_id)
return S_OK;
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);
return hr;
}
if (!(event->scope & (TreeScope_Descendants | TreeScope_Children)))
return S_OK;
V_VT(&prop_cond.Value) = VT_I4 | VT_ARRAY;
V_ARRAY(&prop_cond.Value) = event->runtime_id;
IWineUiaNode_AddRef(&node_data->IWineUiaNode_iface);
while (1)
{
HUIANODE node2 = NULL;
hr = navigate_uia_node(node_data, NavigateDirection_Parent, &node2);
IWineUiaNode_Release(&node_data->IWineUiaNode_iface);
if (FAILED(hr) || !node2)
return hr;
node_data = impl_from_IWineUiaNode((IWineUiaNode *)node2);
hr = uia_condition_check(node2, (struct UiaCondition *)&prop_cond);
if (FAILED(hr))
break;
if (uia_condition_matched(hr))
{
hr = uia_event_invoke(node, args, event);
break;
}
if (!(event->scope & TreeScope_Descendants))
break;
}
IWineUiaNode_Release(&node_data->IWineUiaNode_iface);
return hr;
}
static HRESULT uia_raise_event(IRawElementProviderSimple *elprov, struct UiaEventArgs *args)
{
struct uia_event_map_entry *event_entry;
enum ProviderOptions prov_opts = 0;
struct list *cursor, *cursor2;
HUIANODE node;
SAFEARRAY *sa;
HRESULT hr;
hr = IRawElementProviderSimple_get_ProviderOptions(elprov, &prov_opts);
if (FAILED(hr))
return hr;
EnterCriticalSection(&event_map_cs);
if ((event_entry = uia_get_event_map_entry_for_event(args->EventId)))
InterlockedIncrement(&event_entry->refs);
LeaveCriticalSection(&event_map_cs);
if (!event_entry)
return S_OK;
/*
* For events raised on server-side providers, we don't want to add any
* clientside HWND providers.
*/
if (prov_opts & ProviderOptions_ServerSideProvider)
hr = create_uia_node_from_elprov(elprov, &node, FALSE);
else
hr = create_uia_node_from_elprov(elprov, &node, TRUE);
if (FAILED(hr))
{
uia_event_map_entry_release(event_entry);
return hr;
}
hr = UiaGetRuntimeId(node, &sa);
if (FAILED(hr))
{
uia_event_map_entry_release(event_entry);
UiaNodeRelease(node);
return hr;
}
LIST_FOR_EACH_SAFE(cursor, cursor2, &event_entry->events_list)
{
struct uia_event *event = LIST_ENTRY(cursor, struct uia_event, event_list_entry);
hr = uia_event_check_match(node, sa, args, event);
if (FAILED(hr))
break;
}
uia_event_map_entry_release(event_entry);
SafeArrayDestroy(sa);
UiaNodeRelease(node);
return hr;
}
/***********************************************************************
* UiaRaiseAutomationEvent (uiautomationcore.@)
*/
HRESULT WINAPI UiaRaiseAutomationEvent(IRawElementProviderSimple *elprov, EVENTID id)
{
const struct uia_event_info *event_info = uia_event_info_from_id(id);
struct UiaEventArgs args = { EventArgsType_Simple, id };
HRESULT hr;
TRACE("(%p, %d)\n", elprov, id);
if (!elprov)
return E_INVALIDARG;
if (!event_info || event_info->event_arg_type != EventArgsType_Simple)
{
if (!event_info)
FIXME("No event info structure for event id %d\n", id);
else
WARN("Wrong event raising function for event args type %d\n", event_info->event_arg_type);
return S_OK;
}
hr = uia_raise_event(elprov, &args);
if (FAILED(hr))
return hr;
return S_OK;
}
......@@ -299,15 +299,6 @@ HRESULT WINAPI UiaGetReservedNotSupportedValue(IUnknown **value)
}
/***********************************************************************
* UiaRaiseAutomationEvent (uiautomationcore.@)
*/
HRESULT WINAPI UiaRaiseAutomationEvent(IRawElementProviderSimple *provider, EVENTID id)
{
FIXME("(%p, %d): stub\n", provider, id);
return S_OK;
}
/***********************************************************************
* UiaRaiseAutomationPropertyChangedEvent (uiautomationcore.@)
*/
HRESULT WINAPI UiaRaiseAutomationPropertyChangedEvent(IRawElementProviderSimple *provider, PROPERTYID id, VARIANT old, VARIANT new)
......
......@@ -159,8 +159,11 @@ static inline BOOL uia_array_reserve(void **elements, SIZE_T *capacity, SIZE_T c
/* uia_client.c */
int get_node_provider_type_at_idx(struct uia_node *node, int idx) DECLSPEC_HIDDEN;
HRESULT attach_event_to_uia_node(HUIANODE node, struct uia_event *event) DECLSPEC_HIDDEN;
HRESULT navigate_uia_node(struct uia_node *node, int nav_dir, HUIANODE *out_node) DECLSPEC_HIDDEN;
HRESULT create_uia_node_from_elprov(IRawElementProviderSimple *elprov, HUIANODE *out_node,
BOOL get_hwnd_providers) DECLSPEC_HIDDEN;
HRESULT uia_condition_check(HUIANODE node, struct UiaCondition *condition) DECLSPEC_HIDDEN;
BOOL uia_condition_matched(HRESULT hr) DECLSPEC_HIDDEN;
/* uia_com_client.c */
HRESULT create_uia_iface(IUnknown **iface, BOOL is_cui8) DECLSPEC_HIDDEN;
......
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