From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 4 +- dlls/uiautomationcore/uia_classes.idl | 2 + dlls/uiautomationcore/uia_client.c | 46 +++++++++++++++ dlls/uiautomationcore/uia_event.c | 67 +++++++++++++++++++++- dlls/uiautomationcore/uia_private.h | 4 ++ 5 files changed, 119 insertions(+), 4 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index a178487e420..f7afe254aed 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -16717,8 +16717,8 @@ static const struct prov_method_sequence win_event_handler_seq[] = { { &Provider_hwnd2, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */ { &Provider_nc2, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider_hwnd2, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ - { &Provider_nc2, WINEVENT_HANDLER_RESPOND_TO_WINEVENT, METHOD_TODO }, - { &Provider_hwnd2, WINEVENT_HANDLER_RESPOND_TO_WINEVENT, METHOD_TODO }, + { &Provider_nc2, WINEVENT_HANDLER_RESPOND_TO_WINEVENT }, + { &Provider_hwnd2, WINEVENT_HANDLER_RESPOND_TO_WINEVENT }, NODE_CREATE_SEQ_TODO(&Provider_child), { &Provider_child, FRAG_GET_RUNTIME_ID, METHOD_TODO }, { &Provider_child, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ diff --git a/dlls/uiautomationcore/uia_classes.idl b/dlls/uiautomationcore/uia_classes.idl index b1dea2d414d..33284a252c9 100644 --- a/dlls/uiautomationcore/uia_classes.idl +++ b/dlls/uiautomationcore/uia_classes.idl @@ -92,6 +92,8 @@ library UIA_wine_private 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); + HRESULT respond_to_win_event([in]DWORD win_event, [in]ULONG hwnd, [in]LONG obj_id, [in]LONG child_id, + [in]LONG_PTR huiaevent); }
[ diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 1ff3e1a9a46..f50c739ae97 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -378,6 +378,22 @@ static HRESULT attach_event_to_node_provider(IWineUiaNode *node, int idx, HUIAEV return hr; }
+HRESULT respond_to_win_event_on_node_provider(IWineUiaNode *node, int idx, DWORD win_event, HWND hwnd, LONG obj_id, + LONG child_id, struct uia_event *event) +{ + IWineUiaProvider *prov; + HRESULT hr; + + hr = IWineUiaNode_get_provider(node, idx, &prov); + if (FAILED(hr)) + return hr; + + hr = IWineUiaProvider_respond_to_win_event(prov, win_event, HandleToUlong(hwnd), obj_id, child_id, (LONG_PTR)event); + IWineUiaProvider_Release(prov); + + return hr; +} + /* * IWineUiaNode interface. */ @@ -1939,6 +1955,25 @@ exit: return hr; }
+static HRESULT WINAPI uia_provider_respond_to_win_event(IWineUiaProvider *iface, DWORD win_event, ULONG hwnd, LONG obj_id, + LONG child_id, LONG_PTR huiaevent) +{ + struct uia_provider *prov = impl_from_IWineUiaProvider(iface); + struct uia_event *event = (struct uia_event *)huiaevent; + IProxyProviderWinEventHandler *handler; + HRESULT hr; + + hr = IRawElementProviderSimple_QueryInterface(prov->elprov, &IID_IProxyProviderWinEventHandler, (void **)&handler); + if (FAILED(hr)) + return S_OK; + + hr = IProxyProviderWinEventHandler_RespondToWinEvent(handler, win_event, UlongToHandle(hwnd), obj_id, child_id, + &event->u.clientside.IProxyProviderWinEventSink_iface); + IProxyProviderWinEventHandler_Release(handler); + + return hr; +} + static const IWineUiaProviderVtbl uia_provider_vtbl = { uia_provider_QueryInterface, uia_provider_AddRef, @@ -1949,6 +1984,7 @@ static const IWineUiaProviderVtbl uia_provider_vtbl = { uia_provider_navigate, uia_provider_get_focus, uia_provider_attach_event, + uia_provider_respond_to_win_event, };
static HRESULT create_wine_uia_provider(struct uia_node *node, IRawElementProviderSimple *elprov, @@ -2388,6 +2424,15 @@ static HRESULT WINAPI uia_nested_node_provider_attach_event(IWineUiaProvider *if return hr; }
+static HRESULT WINAPI uia_nested_node_provider_respond_to_win_event(IWineUiaProvider *iface, DWORD win_event, ULONG hwnd, + LONG obj_id, LONG child_id, LONG_PTR huiaevent) +{ + FIXME("%p, %#lx, #%lx, %#lx, %#lx, %#Ix: stub\n", iface, win_event, hwnd, obj_id, child_id, huiaevent); + /* This should not be called. */ + assert(0); + return E_FAIL; +} + static const IWineUiaProviderVtbl uia_nested_node_provider_vtbl = { uia_nested_node_provider_QueryInterface, uia_nested_node_provider_AddRef, @@ -2398,6 +2443,7 @@ static const IWineUiaProviderVtbl uia_nested_node_provider_vtbl = { uia_nested_node_provider_navigate, uia_nested_node_provider_get_focus, uia_nested_node_provider_attach_event, + uia_nested_node_provider_respond_to_win_event, };
static BOOL is_nested_node_provider(IWineUiaProvider *iface) diff --git a/dlls/uiautomationcore/uia_event.c b/dlls/uiautomationcore/uia_event.c index ddb8d1d56b6..97171e7bebc 100644 --- a/dlls/uiautomationcore/uia_event.c +++ b/dlls/uiautomationcore/uia_event.c @@ -20,7 +20,6 @@
#include "wine/debug.h" #include "wine/rbtree.h" -#include "assert.h"
WINE_DEFAULT_DEBUG_CHANNEL(uiautomation);
@@ -560,8 +559,10 @@ static HRESULT uia_win_event_for_each_callback(struct uia_event *event, void *da { struct uia_queue_win_event *win_event = (struct uia_queue_win_event *)data; IRawElementProviderSimple *elprov; + struct uia_node *node_data; HUIANODE node; HRESULT hr; + int i;
if (!uia_hwnd_map_check_hwnd(&event->u.clientside.win_event_hwnd_map, win_event->hwnd)) { @@ -591,7 +592,14 @@ static HRESULT uia_win_event_for_each_callback(struct uia_event *event, void *da if (FAILED(hr)) return hr;
- FIXME("IProxyProviderWinEventHandler usage is currently unimplemented.\n"); + node_data = impl_from_IWineUiaNode((IWineUiaNode *)node); + for (i = 0; i < node_data->prov_count; i++) + { + hr = respond_to_win_event_on_node_provider((IWineUiaNode *)node, i, win_event->event_id, win_event->hwnd, win_event->obj_id, + win_event->child_id, event); + if (FAILED(hr)) + break; + }
UiaNodeRelease(node); return S_OK; @@ -993,6 +1001,60 @@ static HRESULT create_uia_event(struct uia_event **out_event, LONG event_cookie, return S_OK; }
+/* + * IProxyProviderWinEventSink interface implementation for clientside events. + */ +static HRESULT WINAPI ProxyEventSink_QueryInterface(IProxyProviderWinEventSink *iface, REFIID riid, void **obj) +{ + *obj = NULL; + if (IsEqualIID(riid, &IID_IProxyProviderWinEventSink) || IsEqualIID(riid, &IID_IUnknown)) + *obj = iface; + else + return E_NOINTERFACE; + + return S_OK; +} + +static ULONG WINAPI ProxyEventSink_AddRef(IProxyProviderWinEventSink *iface) +{ + return 2; +} + +static ULONG WINAPI ProxyEventSink_Release(IProxyProviderWinEventSink *iface) +{ + return 1; +} + +static HRESULT WINAPI ProxyEventSink_AddAutomationPropertyChangedEvent(IProxyProviderWinEventSink *iface, + IRawElementProviderSimple *elprov, PROPERTYID prop_id, VARIANT new_value) +{ + FIXME("%p, %p, %d, %s: stub\n", iface, elprov, prop_id, debugstr_variant(&new_value)); + return E_NOTIMPL; +} + +static HRESULT WINAPI ProxyEventSink_AddAutomationEvent(IProxyProviderWinEventSink *iface, + IRawElementProviderSimple *elprov, EVENTID event_id) +{ + FIXME("%p, %p, %d: stub\n", iface, elprov, event_id); + return S_OK; +} + +static HRESULT WINAPI ProxyEventSink_AddStructureChangedEvent(IProxyProviderWinEventSink *iface, + IRawElementProviderSimple *elprov, enum StructureChangeType structure_change_type, SAFEARRAY *runtime_id) +{ + FIXME("%p, %p, %d, %p: stub\n", iface, elprov, structure_change_type, runtime_id); + return E_NOTIMPL; +} + +static const IProxyProviderWinEventSinkVtbl proxy_event_sink_vtbl = { + ProxyEventSink_QueryInterface, + ProxyEventSink_AddRef, + ProxyEventSink_Release, + ProxyEventSink_AddAutomationPropertyChangedEvent, + ProxyEventSink_AddAutomationEvent, + ProxyEventSink_AddStructureChangedEvent, +}; + static HRESULT create_clientside_uia_event(struct uia_event **out_event, int event_id, int scope, UiaWineEventCallback *cback, void *cback_data, SAFEARRAY *runtime_id) { @@ -1011,6 +1073,7 @@ static HRESULT create_clientside_uia_event(struct uia_event **out_event, int eve event->u.clientside.event_callback = cback; event->u.clientside.callback_data = cback_data; uia_hwnd_map_init(&event->u.clientside.win_event_hwnd_map); + event->u.clientside.IProxyProviderWinEventSink_iface.lpVtbl = &proxy_event_sink_vtbl;
*out_event = event; return S_OK; diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h index abd03ce308e..de6e547dfa4 100644 --- a/dlls/uiautomationcore/uia_private.h +++ b/dlls/uiautomationcore/uia_private.h @@ -22,6 +22,7 @@ #include "uia_classes.h" #include "wine/list.h" #include "wine/rbtree.h" +#include "assert.h"
extern HMODULE huia_module DECLSPEC_HIDDEN;
@@ -143,6 +144,7 @@ struct uia_event HRESULT (*event_callback)(struct uia_event *, struct uia_event_args *, SAFEARRAY *, BSTR); void *callback_data;
+ IProxyProviderWinEventSink IProxyProviderWinEventSink_iface; struct rb_tree win_event_hwnd_map; BOOL event_thread_started; DWORD git_cookie; @@ -210,6 +212,8 @@ 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 respond_to_win_event_on_node_provider(IWineUiaNode *node, int idx, DWORD win_event, HWND hwnd, LONG obj_id, + LONG child_id, struct uia_event *event) DECLSPEC_HIDDEN; HRESULT attach_event_to_uia_node(HUIANODE node, struct uia_event *event) DECLSPEC_HIDDEN; HRESULT clone_uia_node(HUIANODE in_node, HUIANODE *out_node) DECLSPEC_HIDDEN; HRESULT navigate_uia_node(struct uia_node *node, int nav_dir, HUIANODE *out_node) DECLSPEC_HIDDEN;