mirror of
git://source.winehq.org/git/wine.git
synced 2024-09-02 21:03:39 +00:00
uiautomationcore: Call IRawElementProviderAdviseEvents methods when events are added or removed.
Signed-off-by: Connor McAdams <cmcadams@codeweavers.com>
This commit is contained in:
parent
973d00db1b
commit
a5426f6ace
|
@ -13714,12 +13714,12 @@ static const struct prov_method_sequence event_seq1[] = {
|
|||
static const struct prov_method_sequence event_seq2[] = {
|
||||
{ &Provider, FRAG_GET_RUNTIME_ID },
|
||||
{ &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */
|
||||
{ &Provider, FRAG_GET_FRAGMENT_ROOT, METHOD_TODO },
|
||||
{ &Provider, FRAG_GET_FRAGMENT_ROOT },
|
||||
{ &Provider, FRAG_GET_FRAGMENT_ROOT, METHOD_OPTIONAL }, /* Called twice on Win11. */
|
||||
NODE_CREATE_SEQ_OPTIONAL(&Provider), /* Only done in Win11. */
|
||||
{ &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win8+. */
|
||||
{ &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */
|
||||
{ &Provider, ADVISE_EVENTS_EVENT_ADDED, METHOD_TODO },
|
||||
{ &Provider, ADVISE_EVENTS_EVENT_ADDED },
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
|
@ -13737,25 +13737,25 @@ static const struct prov_method_sequence event_seq3[] = {
|
|||
};
|
||||
|
||||
static const struct prov_method_sequence event_seq4[] = {
|
||||
{ &Provider, ADVISE_EVENTS_EVENT_REMOVED, METHOD_TODO },
|
||||
{ &Provider, ADVISE_EVENTS_EVENT_REMOVED },
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
static const struct prov_method_sequence event_seq5[] = {
|
||||
{ &Provider, FRAG_GET_RUNTIME_ID },
|
||||
{ &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */
|
||||
{ &Provider, FRAG_GET_FRAGMENT_ROOT, METHOD_TODO },
|
||||
{ &Provider, FRAG_GET_FRAGMENT_ROOT },
|
||||
{ &Provider, FRAG_GET_FRAGMENT_ROOT, METHOD_OPTIONAL }, /* Called twice on Win11. */
|
||||
{ &Provider, FRAG_GET_EMBEDDED_FRAGMENT_ROOTS, METHOD_TODO },
|
||||
NODE_CREATE_SEQ_OPTIONAL(&Provider), /* Only done in Win11. */
|
||||
{ &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, /* Only done on Win8+. */
|
||||
{ &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */
|
||||
{ &Provider, ADVISE_EVENTS_EVENT_ADDED, METHOD_TODO },
|
||||
{ &Provider, ADVISE_EVENTS_EVENT_ADDED },
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
static const struct prov_method_sequence event_seq6[] = {
|
||||
{ &Provider, ADVISE_EVENTS_EVENT_REMOVED, METHOD_TODO },
|
||||
{ &Provider, ADVISE_EVENTS_EVENT_REMOVED },
|
||||
{ &Provider_child, ADVISE_EVENTS_EVENT_REMOVED, METHOD_TODO },
|
||||
{ &Provider_child2, ADVISE_EVENTS_EVENT_REMOVED, METHOD_TODO },
|
||||
{ 0 },
|
||||
|
@ -13812,7 +13812,7 @@ static DWORD WINAPI uia_add_event_test_thread(LPVOID param)
|
|||
ok(Provider2.ref == 1, "Unexpected refcnt %ld\n", Provider2.ref);
|
||||
todo_wine ok(Provider2.last_call_tid == data->exp_thread_id ||
|
||||
broken(Provider2.last_call_tid == GetCurrentThreadId()), "Expected method call on separate thread\n");
|
||||
todo_wine ok(Provider2.advise_events_removed_event_id == UIA_AutomationFocusChangedEventId,
|
||||
ok(Provider2.advise_events_removed_event_id == UIA_AutomationFocusChangedEventId,
|
||||
"Unexpected advise event removed, event ID %d\n", Provider.advise_events_removed_event_id);
|
||||
|
||||
CoUninitialize();
|
||||
|
@ -13931,7 +13931,7 @@ static void test_UiaAddEvent(void)
|
|||
&event);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
ok(!!event, "event == NULL\n");
|
||||
todo_wine ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref);
|
||||
ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref);
|
||||
ok_method_sequence(event_seq2, "event_seq2");
|
||||
|
||||
/*
|
||||
|
@ -13965,7 +13965,7 @@ static void test_UiaAddEvent(void)
|
|||
&event);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
ok(!!event, "event == NULL\n");
|
||||
todo_wine ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref);
|
||||
ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref);
|
||||
ok_method_sequence(event_seq2, "event_seq2");
|
||||
|
||||
/* Event callback is now invoked since we can match by runtime ID. */
|
||||
|
@ -14005,7 +14005,7 @@ static void test_UiaAddEvent(void)
|
|||
&event);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
ok(!!event, "event == NULL\n");
|
||||
todo_wine ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref);
|
||||
ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref);
|
||||
ok_method_sequence(event_seq5, "event_seq5");
|
||||
|
||||
/*
|
||||
|
@ -14052,7 +14052,7 @@ static void test_UiaAddEvent(void)
|
|||
&cache_req, &event);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
ok(!!event, "event == NULL\n");
|
||||
todo_wine ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref);
|
||||
ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref);
|
||||
|
||||
/* Raised an event on Provider_child_child. */
|
||||
init_node_provider_desc(&exp_node_desc, GetCurrentProcessId(), NULL);
|
||||
|
@ -14086,9 +14086,9 @@ static void test_UiaAddEvent(void)
|
|||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
ok(!!event, "event == NULL\n");
|
||||
ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref);
|
||||
todo_wine ok(Provider2.ref > 1, "Unexpected refcnt %ld\n", Provider2.ref);
|
||||
ok(Provider2.ref > 1, "Unexpected refcnt %ld\n", Provider2.ref);
|
||||
ok(!Provider.advise_events_added_event_id, "Unexpected advise event added, event ID %d\n", Provider.advise_events_added_event_id);
|
||||
todo_wine ok(Provider2.advise_events_added_event_id == UIA_AutomationFocusChangedEventId,
|
||||
ok(Provider2.advise_events_added_event_id == UIA_AutomationFocusChangedEventId,
|
||||
"Unexpected advise event added, event ID %d\n", Provider.advise_events_added_event_id);
|
||||
|
||||
thread_data.exp_thread_id = GetCurrentThreadId();
|
||||
|
@ -14120,10 +14120,10 @@ static void test_UiaAddEvent(void)
|
|||
&cache_req, &event);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
ok(!!event, "event == NULL\n");
|
||||
todo_wine ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref);
|
||||
ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref);
|
||||
todo_wine ok(Provider_child.ref == 2, "Unexpected refcnt %ld\n", Provider_child.ref);
|
||||
todo_wine ok(Provider_child2.ref == 2, "Unexpected refcnt %ld\n", Provider_child2.ref);
|
||||
todo_wine ok(Provider.advise_events_added_event_id == UIA_AutomationFocusChangedEventId,
|
||||
ok(Provider.advise_events_added_event_id == UIA_AutomationFocusChangedEventId,
|
||||
"Unexpected advise event added, event ID %d\n", Provider.advise_events_added_event_id);
|
||||
todo_wine ok(Provider_child.advise_events_added_event_id == UIA_AutomationFocusChangedEventId,
|
||||
"Unexpected advise event added, event ID %d\n", Provider_child.advise_events_added_event_id);
|
||||
|
|
|
@ -61,6 +61,7 @@ library UIA_wine_private
|
|||
]
|
||||
interface IWineUiaEvent : IUnknown
|
||||
{
|
||||
HRESULT advise_events([in]BOOL advise_added);
|
||||
}
|
||||
|
||||
[
|
||||
|
@ -76,6 +77,7 @@ library UIA_wine_private
|
|||
HRESULT has_parent([out, retval]BOOL *out_val);
|
||||
HRESULT navigate([in]int nav_dir, [out, retval]VARIANT *ret_val);
|
||||
HRESULT get_focus([out, retval]VARIANT *ret_val);
|
||||
HRESULT attach_event([in]LONG_PTR huiaevent);
|
||||
}
|
||||
|
||||
[
|
||||
|
|
|
@ -462,6 +462,21 @@ static HRESULT get_focus_from_node_provider(IWineUiaNode *node, int idx, VARIANT
|
|||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT attach_event_to_node_provider(IWineUiaNode *node, int idx, HUIAEVENT huiaevent)
|
||||
{
|
||||
IWineUiaProvider *prov;
|
||||
HRESULT hr;
|
||||
|
||||
hr = IWineUiaNode_get_provider(node, idx, &prov);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
hr = IWineUiaProvider_attach_event(prov, (LONG_PTR)huiaevent);
|
||||
IWineUiaProvider_Release(prov);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
/*
|
||||
* IWineUiaNode interface.
|
||||
*/
|
||||
|
@ -1285,6 +1300,22 @@ exit:
|
|||
return hr;
|
||||
}
|
||||
|
||||
HRESULT attach_event_to_uia_node(HUIANODE node, struct uia_event *event)
|
||||
{
|
||||
struct uia_node *node_data = impl_from_IWineUiaNode((IWineUiaNode *)node);
|
||||
HRESULT hr = S_OK;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < node_data->prov_count; i++)
|
||||
{
|
||||
hr = attach_event_to_node_provider(&node_data->IWineUiaNode_iface, i, (HUIAEVENT)event);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
/*
|
||||
* IWineUiaProvider interface.
|
||||
*/
|
||||
|
@ -1813,6 +1844,44 @@ static HRESULT WINAPI uia_provider_get_focus(IWineUiaProvider *iface, VARIANT *o
|
|||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI uia_provider_attach_event(IWineUiaProvider *iface, LONG_PTR huiaevent)
|
||||
{
|
||||
struct uia_provider *prov = impl_from_IWineUiaProvider(iface);
|
||||
struct uia_event *event = (struct uia_event *)huiaevent;
|
||||
IRawElementProviderFragmentRoot *elroot;
|
||||
IRawElementProviderFragment *elfrag;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("%p, %#Ix\n", iface, huiaevent);
|
||||
|
||||
hr = IRawElementProviderSimple_QueryInterface(prov->elprov, &IID_IRawElementProviderFragment, (void **)&elfrag);
|
||||
if (FAILED(hr))
|
||||
return S_OK;
|
||||
|
||||
hr = IRawElementProviderFragment_get_FragmentRoot(elfrag, &elroot);
|
||||
IRawElementProviderFragment_Release(elfrag);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
if (elroot)
|
||||
{
|
||||
IRawElementProviderAdviseEvents *advise_events;
|
||||
|
||||
hr = IRawElementProviderFragmentRoot_QueryInterface(elroot, &IID_IRawElementProviderAdviseEvents,
|
||||
(void **)&advise_events);
|
||||
IRawElementProviderFragmentRoot_Release(elroot);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = uia_event_add_provider_event_adviser(advise_events, event);
|
||||
IRawElementProviderAdviseEvents_Release(advise_events);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static const IWineUiaProviderVtbl uia_provider_vtbl = {
|
||||
uia_provider_QueryInterface,
|
||||
uia_provider_AddRef,
|
||||
|
@ -1822,6 +1891,7 @@ static const IWineUiaProviderVtbl uia_provider_vtbl = {
|
|||
uia_provider_has_parent,
|
||||
uia_provider_navigate,
|
||||
uia_provider_get_focus,
|
||||
uia_provider_attach_event,
|
||||
};
|
||||
|
||||
static HRESULT create_wine_uia_provider(struct uia_node *node, IRawElementProviderSimple *elprov,
|
||||
|
@ -2246,6 +2316,12 @@ static HRESULT WINAPI uia_nested_node_provider_get_focus(IWineUiaProvider *iface
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI uia_nested_node_provider_attach_event(IWineUiaProvider *iface, LONG_PTR huiaevent)
|
||||
{
|
||||
FIXME("%p, %#Ix: stub\n", iface, huiaevent);
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static const IWineUiaProviderVtbl uia_nested_node_provider_vtbl = {
|
||||
uia_nested_node_provider_QueryInterface,
|
||||
uia_nested_node_provider_AddRef,
|
||||
|
@ -2255,6 +2331,7 @@ static const IWineUiaProviderVtbl uia_nested_node_provider_vtbl = {
|
|||
uia_nested_node_provider_has_parent,
|
||||
uia_nested_node_provider_navigate,
|
||||
uia_nested_node_provider_get_focus,
|
||||
uia_nested_node_provider_attach_event,
|
||||
};
|
||||
|
||||
static BOOL is_nested_node_provider(IWineUiaProvider *iface)
|
||||
|
|
|
@ -22,18 +22,6 @@
|
|||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(uiautomation);
|
||||
|
||||
struct uia_event
|
||||
{
|
||||
IWineUiaEvent IWineUiaEvent_iface;
|
||||
LONG ref;
|
||||
|
||||
SAFEARRAY *runtime_id;
|
||||
int event_id;
|
||||
int scope;
|
||||
|
||||
UiaEventCallback *cback;
|
||||
};
|
||||
|
||||
/*
|
||||
* IWineUiaEvent interface.
|
||||
*/
|
||||
|
@ -71,17 +59,55 @@ static ULONG WINAPI uia_event_Release(IWineUiaEvent *iface)
|
|||
TRACE("%p, refcount %ld\n", event, ref);
|
||||
if (!ref)
|
||||
{
|
||||
int i;
|
||||
|
||||
SafeArrayDestroy(event->runtime_id);
|
||||
for (i = 0; i < event->event_advisers_count; i++)
|
||||
IRawElementProviderAdviseEvents_Release(event->event_advisers[i]);
|
||||
heap_free(event->event_advisers);
|
||||
heap_free(event);
|
||||
}
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI uia_event_advise_events(IWineUiaEvent *iface, BOOL advise_added)
|
||||
{
|
||||
struct uia_event *event = impl_from_IWineUiaEvent(iface);
|
||||
HRESULT hr;
|
||||
int i;
|
||||
|
||||
TRACE("%p, %d\n", event, advise_added);
|
||||
|
||||
for (i = 0; i < event->event_advisers_count; i++)
|
||||
{
|
||||
IRawElementProviderAdviseEvents *adviser = event->event_advisers[i];
|
||||
|
||||
if (advise_added)
|
||||
hr = IRawElementProviderAdviseEvents_AdviseEventAdded(adviser, event->event_id, NULL);
|
||||
else
|
||||
hr = IRawElementProviderAdviseEvents_AdviseEventRemoved(adviser, event->event_id, NULL);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
}
|
||||
|
||||
/* Once we've advised of removal, no need to keep the advisers around. */
|
||||
if (!advise_added)
|
||||
{
|
||||
for (i = 0; i < event->event_advisers_count; i++)
|
||||
IRawElementProviderAdviseEvents_Release(event->event_advisers[i]);
|
||||
heap_free(event->event_advisers);
|
||||
event->event_advisers_count = event->event_advisers_arr_size = 0;
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static const IWineUiaEventVtbl uia_event_vtbl = {
|
||||
uia_event_QueryInterface,
|
||||
uia_event_AddRef,
|
||||
uia_event_Release,
|
||||
uia_event_advise_events,
|
||||
};
|
||||
|
||||
static struct uia_event *unsafe_impl_from_IWineUiaEvent(IWineUiaEvent *iface)
|
||||
|
@ -112,6 +138,19 @@ static HRESULT create_uia_event(struct uia_event **out_event, int event_id, int
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT uia_event_add_provider_event_adviser(IRawElementProviderAdviseEvents *advise_events, struct uia_event *event)
|
||||
{
|
||||
if (!uia_array_reserve((void **)&event->event_advisers, &event->event_advisers_arr_size,
|
||||
event->event_advisers_count + 1, sizeof(*event->event_advisers)))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
event->event_advisers[event->event_advisers_count] = advise_events;
|
||||
IRawElementProviderAdviseEvents_AddRef(advise_events);
|
||||
event->event_advisers_count++;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* UiaAddEvent (uiautomationcore.@)
|
||||
*/
|
||||
|
@ -150,9 +189,21 @@ HRESULT WINAPI UiaAddEvent(HUIANODE huianode, EVENTID event_id, UiaEventCallback
|
|||
return hr;
|
||||
}
|
||||
|
||||
hr = attach_event_to_uia_node(huianode, event);
|
||||
if (FAILED(hr))
|
||||
goto exit;
|
||||
|
||||
hr = IWineUiaEvent_advise_events(&event->IWineUiaEvent_iface, TRUE);
|
||||
if (FAILED(hr))
|
||||
goto exit;
|
||||
|
||||
*huiaevent = (HUIAEVENT)event;
|
||||
|
||||
return S_OK;
|
||||
exit:
|
||||
if (FAILED(hr))
|
||||
IWineUiaEvent_Release(&event->IWineUiaEvent_iface);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
@ -161,12 +212,17 @@ HRESULT WINAPI UiaAddEvent(HUIANODE huianode, EVENTID event_id, UiaEventCallback
|
|||
HRESULT WINAPI UiaRemoveEvent(HUIAEVENT huiaevent)
|
||||
{
|
||||
struct uia_event *event = unsafe_impl_from_IWineUiaEvent((IWineUiaEvent *)huiaevent);
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("(%p)\n", event);
|
||||
|
||||
if (!event)
|
||||
return E_INVALIDARG;
|
||||
|
||||
hr = IWineUiaEvent_advise_events(&event->IWineUiaEvent_iface, FALSE);
|
||||
IWineUiaEvent_Release(&event->IWineUiaEvent_iface);
|
||||
if (FAILED(hr))
|
||||
WARN("advise_events failed with hr %#lx\n", hr);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
|
|
@ -93,6 +93,22 @@ static inline struct uia_provider *impl_from_IWineUiaProvider(IWineUiaProvider *
|
|||
return CONTAINING_RECORD(iface, struct uia_provider, IWineUiaProvider_iface);
|
||||
}
|
||||
|
||||
struct uia_event
|
||||
{
|
||||
IWineUiaEvent IWineUiaEvent_iface;
|
||||
LONG ref;
|
||||
|
||||
SAFEARRAY *runtime_id;
|
||||
int event_id;
|
||||
int scope;
|
||||
|
||||
IRawElementProviderAdviseEvents **event_advisers;
|
||||
int event_advisers_count;
|
||||
SIZE_T event_advisers_arr_size;
|
||||
|
||||
UiaEventCallback *cback;
|
||||
};
|
||||
|
||||
static inline void variant_init_bool(VARIANT *v, BOOL val)
|
||||
{
|
||||
V_VT(v) = VT_BOOL;
|
||||
|
@ -139,12 +155,17 @@ static inline BOOL uia_array_reserve(void **elements, SIZE_T *capacity, SIZE_T c
|
|||
HRESULT get_safearray_bounds(SAFEARRAY *sa, LONG *lbound, LONG *elems) DECLSPEC_HIDDEN;
|
||||
int uia_compare_safearrays(SAFEARRAY *sa1, SAFEARRAY *sa2, int prop_type) DECLSPEC_HIDDEN;
|
||||
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 create_uia_node_from_elprov(IRawElementProviderSimple *elprov, HUIANODE *out_node,
|
||||
BOOL get_hwnd_providers) DECLSPEC_HIDDEN;
|
||||
|
||||
/* uia_com_client.c */
|
||||
HRESULT create_uia_iface(IUnknown **iface, BOOL is_cui8) DECLSPEC_HIDDEN;
|
||||
|
||||
/* uia_event.c */
|
||||
HRESULT uia_event_add_provider_event_adviser(IRawElementProviderAdviseEvents *advise_events,
|
||||
struct uia_event *event) DECLSPEC_HIDDEN;
|
||||
|
||||
/* uia_ids.c */
|
||||
const struct uia_prop_info *uia_prop_info_from_id(PROPERTYID prop_id) DECLSPEC_HIDDEN;
|
||||
const struct uia_event_info *uia_event_info_from_id(EVENTID event_id) DECLSPEC_HIDDEN;
|
||||
|
|
Loading…
Reference in a new issue