uiautomationcore/tests: Add tests for IProxyProviderWinEventHandler based MSAA to UIA event bridging.
Signed-off-by: Connor McAdams <cmcadams@codeweavers.com>
This commit is contained in:
parent
ed2bfd4ad7
commit
87af89cb3b
1 changed files with 655 additions and 20 deletions
|
@ -391,6 +391,7 @@ DEFINE_EXPECT(prov_callback_nonclient);
|
|||
DEFINE_EXPECT(prov_callback_proxy);
|
||||
DEFINE_EXPECT(prov_callback_parent_proxy);
|
||||
DEFINE_EXPECT(uia_event_callback);
|
||||
DEFINE_EXPECT(uia_event_callback2);
|
||||
DEFINE_EXPECT(uia_com_event_callback);
|
||||
DEFINE_EXPECT(winproc_GETOBJECT_UiaRoot);
|
||||
DEFINE_EXPECT(child_winproc_GETOBJECT_UiaRoot);
|
||||
|
@ -493,6 +494,34 @@ static void test_implements_interface_(IUnknown *unk, const GUID *iid, BOOL exp_
|
|||
DEFINE_ACC_METHOD_EXPECT(get_locale); \
|
||||
DEFINE_ACC_METHOD_EXPECT(get_attributes) \
|
||||
|
||||
static DWORD msg_wait_for_all_events(HANDLE *event_handles, int event_handle_count, DWORD timeout_val)
|
||||
{
|
||||
int events_handled = 0;
|
||||
DWORD wait_res;
|
||||
|
||||
while ((wait_res = MsgWaitForMultipleObjects(event_handle_count, (const HANDLE *)event_handles, FALSE, timeout_val,
|
||||
QS_ALLINPUT)) <= (WAIT_OBJECT_0 + event_handle_count))
|
||||
{
|
||||
if (wait_res == (WAIT_OBJECT_0 + event_handle_count))
|
||||
{
|
||||
MSG msg;
|
||||
|
||||
while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
}
|
||||
else
|
||||
events_handled++;
|
||||
|
||||
if (events_handled == event_handle_count)
|
||||
break;
|
||||
}
|
||||
|
||||
return wait_res;
|
||||
}
|
||||
|
||||
static struct Accessible
|
||||
{
|
||||
IAccessible IAccessible_iface;
|
||||
|
@ -1555,6 +1584,19 @@ struct Provider_legacy_accessible_pattern_data
|
|||
DWORD role;
|
||||
};
|
||||
|
||||
struct Provider_win_event_handler_data
|
||||
{
|
||||
BOOL is_supported;
|
||||
|
||||
DWORD exp_win_event_id;
|
||||
HWND exp_win_event_hwnd;
|
||||
LONG exp_win_event_obj_id;
|
||||
LONG exp_win_event_child_id;
|
||||
|
||||
IRawElementProviderSimple *responder_prov;
|
||||
int responder_event;
|
||||
};
|
||||
|
||||
static struct Provider
|
||||
{
|
||||
IRawElementProviderSimple IRawElementProviderSimple_iface;
|
||||
|
@ -1562,6 +1604,7 @@ static struct Provider
|
|||
IRawElementProviderFragmentRoot IRawElementProviderFragmentRoot_iface;
|
||||
IRawElementProviderHwndOverride IRawElementProviderHwndOverride_iface;
|
||||
IRawElementProviderAdviseEvents IRawElementProviderAdviseEvents_iface;
|
||||
IProxyProviderWinEventHandler IProxyProviderWinEventHandler_iface;
|
||||
IValueProvider IValueProvider_iface;
|
||||
ILegacyIAccessibleProvider ILegacyIAccessibleProvider_iface;
|
||||
LONG ref;
|
||||
|
@ -1591,6 +1634,7 @@ static struct Provider
|
|||
int embedded_frag_roots_count;
|
||||
int advise_events_added_event_id;
|
||||
int advise_events_removed_event_id;
|
||||
struct Provider_win_event_handler_data win_event_handler_data;
|
||||
} Provider, Provider2, Provider_child, Provider_child2;
|
||||
static struct Provider Provider_hwnd, Provider_nc, Provider_proxy, Provider_proxy2, Provider_override;
|
||||
static void initialize_provider(struct Provider *prov, int prov_opts, HWND hwnd, BOOL initialize_nav_links);
|
||||
|
@ -1662,6 +1706,7 @@ enum {
|
|||
HWND_OVERRIDE_GET_OVERRIDE_PROVIDER,
|
||||
ADVISE_EVENTS_EVENT_ADDED,
|
||||
ADVISE_EVENTS_EVENT_REMOVED,
|
||||
WINEVENT_HANDLER_RESPOND_TO_WINEVENT,
|
||||
};
|
||||
|
||||
static const char *prov_method_str[] = {
|
||||
|
@ -1678,6 +1723,7 @@ static const char *prov_method_str[] = {
|
|||
"GetOverrideProviderForHwnd",
|
||||
"AdviseEventAdded",
|
||||
"AdviseEventRemoved",
|
||||
"RespondToWinEvent",
|
||||
};
|
||||
|
||||
static const char *get_prov_method_str(int method)
|
||||
|
@ -2061,6 +2107,8 @@ HRESULT WINAPI ProviderSimple_QueryInterface(IRawElementProviderSimple *iface, R
|
|||
*ppv = &This->IValueProvider_iface;
|
||||
else if (IsEqualIID(riid, &IID_ILegacyIAccessibleProvider))
|
||||
*ppv = &This->ILegacyIAccessibleProvider_iface;
|
||||
else if (This->win_event_handler_data.is_supported && IsEqualIID(riid, &IID_IProxyProviderWinEventHandler))
|
||||
*ppv = &This->IProxyProviderWinEventHandler_iface;
|
||||
else
|
||||
return E_NOINTERFACE;
|
||||
|
||||
|
@ -2723,6 +2771,64 @@ static const IRawElementProviderAdviseEventsVtbl ProviderAdviseEventsVtbl = {
|
|||
ProviderAdviseEvents_AdviseEventRemoved,
|
||||
};
|
||||
|
||||
static inline struct Provider *impl_from_ProviderWinEventHandler(IProxyProviderWinEventHandler *iface)
|
||||
{
|
||||
return CONTAINING_RECORD(iface, struct Provider, IProxyProviderWinEventHandler_iface);
|
||||
}
|
||||
|
||||
static HRESULT WINAPI ProviderWinEventHandler_QueryInterface(IProxyProviderWinEventHandler *iface, REFIID riid,
|
||||
void **ppv)
|
||||
{
|
||||
struct Provider *Provider = impl_from_ProviderWinEventHandler(iface);
|
||||
return IRawElementProviderSimple_QueryInterface(&Provider->IRawElementProviderSimple_iface, riid, ppv);
|
||||
}
|
||||
|
||||
static ULONG WINAPI ProviderWinEventHandler_AddRef(IProxyProviderWinEventHandler *iface)
|
||||
{
|
||||
struct Provider *Provider = impl_from_ProviderWinEventHandler(iface);
|
||||
return IRawElementProviderSimple_AddRef(&Provider->IRawElementProviderSimple_iface);
|
||||
}
|
||||
|
||||
static ULONG WINAPI ProviderWinEventHandler_Release(IProxyProviderWinEventHandler *iface)
|
||||
{
|
||||
struct Provider *Provider = impl_from_ProviderWinEventHandler(iface);
|
||||
return IRawElementProviderSimple_Release(&Provider->IRawElementProviderSimple_iface);
|
||||
}
|
||||
|
||||
static HRESULT WINAPI ProviderWinEventHandler_RespondToWinEvent(IProxyProviderWinEventHandler *iface,
|
||||
DWORD event_id, HWND hwnd, LONG obj_id, LONG child_id, IProxyProviderWinEventSink *event_sink)
|
||||
{
|
||||
struct Provider *This = impl_from_ProviderWinEventHandler(iface);
|
||||
struct Provider_win_event_handler_data *data;
|
||||
HRESULT hr;
|
||||
|
||||
PROV_METHOD_TRACE(This, RespondToWinEvent);
|
||||
data = &This->win_event_handler_data;
|
||||
if ((data->exp_win_event_id != event_id) || (data->exp_win_event_hwnd != hwnd) || (data->exp_win_event_obj_id != obj_id) ||
|
||||
(data->exp_win_event_child_id != child_id))
|
||||
return S_OK;
|
||||
|
||||
add_method_call(This, WINEVENT_HANDLER_RESPOND_TO_WINEVENT);
|
||||
if (This->expected_tid)
|
||||
ok(This->expected_tid == GetCurrentThreadId(), "Unexpected tid %ld\n", GetCurrentThreadId());
|
||||
This->last_call_tid = GetCurrentThreadId();
|
||||
|
||||
if (data->responder_prov)
|
||||
{
|
||||
hr = IProxyProviderWinEventSink_AddAutomationEvent(event_sink, data->responder_prov, data->responder_event);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static const IProxyProviderWinEventHandlerVtbl ProviderWinEventHandlerVtbl = {
|
||||
ProviderWinEventHandler_QueryInterface,
|
||||
ProviderWinEventHandler_AddRef,
|
||||
ProviderWinEventHandler_Release,
|
||||
ProviderWinEventHandler_RespondToWinEvent,
|
||||
};
|
||||
|
||||
static inline struct Provider *impl_from_ProviderValuePattern(IValueProvider *iface)
|
||||
{
|
||||
return CONTAINING_RECORD(iface, struct Provider, IValueProvider_iface);
|
||||
|
@ -2921,6 +3027,7 @@ static struct Provider Provider =
|
|||
{ &ProviderFragmentRootVtbl },
|
||||
{ &ProviderHwndOverrideVtbl },
|
||||
{ &ProviderAdviseEventsVtbl },
|
||||
{ &ProviderWinEventHandlerVtbl },
|
||||
{ &ProviderValuePatternVtbl },
|
||||
{ &ProviderLegacyIAccessiblePatternVtbl },
|
||||
1,
|
||||
|
@ -2938,6 +3045,7 @@ static struct Provider Provider2 =
|
|||
{ &ProviderFragmentRootVtbl },
|
||||
{ &ProviderHwndOverrideVtbl },
|
||||
{ &ProviderAdviseEventsVtbl },
|
||||
{ &ProviderWinEventHandlerVtbl },
|
||||
{ &ProviderValuePatternVtbl },
|
||||
{ &ProviderLegacyIAccessiblePatternVtbl },
|
||||
1,
|
||||
|
@ -2955,6 +3063,7 @@ static struct Provider Provider_child =
|
|||
{ &ProviderFragmentRootVtbl },
|
||||
{ &ProviderHwndOverrideVtbl },
|
||||
{ &ProviderAdviseEventsVtbl },
|
||||
{ &ProviderWinEventHandlerVtbl },
|
||||
{ &ProviderValuePatternVtbl },
|
||||
{ &ProviderLegacyIAccessiblePatternVtbl },
|
||||
1,
|
||||
|
@ -2972,6 +3081,7 @@ static struct Provider Provider_child2 =
|
|||
{ &ProviderFragmentRootVtbl },
|
||||
{ &ProviderHwndOverrideVtbl },
|
||||
{ &ProviderAdviseEventsVtbl },
|
||||
{ &ProviderWinEventHandlerVtbl },
|
||||
{ &ProviderValuePatternVtbl },
|
||||
{ &ProviderLegacyIAccessiblePatternVtbl },
|
||||
1,
|
||||
|
@ -2989,6 +3099,7 @@ static struct Provider Provider_hwnd =
|
|||
{ &ProviderFragmentRootVtbl },
|
||||
{ &ProviderHwndOverrideVtbl },
|
||||
{ &ProviderAdviseEventsVtbl },
|
||||
{ &ProviderWinEventHandlerVtbl },
|
||||
{ &ProviderValuePatternVtbl },
|
||||
{ &ProviderLegacyIAccessiblePatternVtbl },
|
||||
1,
|
||||
|
@ -3006,6 +3117,7 @@ static struct Provider Provider_nc =
|
|||
{ &ProviderFragmentRootVtbl },
|
||||
{ &ProviderHwndOverrideVtbl },
|
||||
{ &ProviderAdviseEventsVtbl },
|
||||
{ &ProviderWinEventHandlerVtbl },
|
||||
{ &ProviderValuePatternVtbl },
|
||||
{ &ProviderLegacyIAccessiblePatternVtbl },
|
||||
1,
|
||||
|
@ -3024,6 +3136,7 @@ static struct Provider Provider_proxy =
|
|||
{ &ProviderFragmentRootVtbl },
|
||||
{ &ProviderHwndOverrideVtbl },
|
||||
{ &ProviderAdviseEventsVtbl },
|
||||
{ &ProviderWinEventHandlerVtbl },
|
||||
{ &ProviderValuePatternVtbl },
|
||||
{ &ProviderLegacyIAccessiblePatternVtbl },
|
||||
1,
|
||||
|
@ -3042,6 +3155,7 @@ static struct Provider Provider_proxy2 =
|
|||
{ &ProviderFragmentRootVtbl },
|
||||
{ &ProviderHwndOverrideVtbl },
|
||||
{ &ProviderAdviseEventsVtbl },
|
||||
{ &ProviderWinEventHandlerVtbl },
|
||||
{ &ProviderValuePatternVtbl },
|
||||
{ &ProviderLegacyIAccessiblePatternVtbl },
|
||||
1,
|
||||
|
@ -3060,6 +3174,7 @@ static struct Provider Provider_override =
|
|||
{ &ProviderFragmentRootVtbl },
|
||||
{ &ProviderHwndOverrideVtbl },
|
||||
{ &ProviderAdviseEventsVtbl },
|
||||
{ &ProviderWinEventHandlerVtbl },
|
||||
{ &ProviderValuePatternVtbl },
|
||||
{ &ProviderLegacyIAccessiblePatternVtbl },
|
||||
1,
|
||||
|
@ -3079,6 +3194,7 @@ static struct Provider Provider_override =
|
|||
{ &ProviderFragmentRootVtbl }, \
|
||||
{ &ProviderHwndOverrideVtbl }, \
|
||||
{ &ProviderAdviseEventsVtbl }, \
|
||||
{ &ProviderWinEventHandlerVtbl }, \
|
||||
{ &ProviderValuePatternVtbl }, \
|
||||
{ &ProviderLegacyIAccessiblePatternVtbl }, \
|
||||
1, \
|
||||
|
@ -10793,6 +10909,37 @@ static void set_property_override(struct Provider_prop_override *override, int p
|
|||
override->val = *val;
|
||||
}
|
||||
|
||||
static void set_provider_win_event_handler_respond_prov(struct Provider *prov, IRawElementProviderSimple *responder_prov,
|
||||
int responder_event)
|
||||
{
|
||||
struct Provider_win_event_handler_data *data = &prov->win_event_handler_data;
|
||||
|
||||
data->responder_prov = responder_prov;
|
||||
data->responder_event = responder_event;
|
||||
}
|
||||
|
||||
static void set_provider_win_event_handler_win_event_expects(struct Provider *prov, DWORD exp_win_event_id,
|
||||
HWND exp_win_event_hwnd, LONG exp_win_event_obj_id, LONG exp_win_event_child_id)
|
||||
{
|
||||
struct Provider_win_event_handler_data *data = &prov->win_event_handler_data;
|
||||
|
||||
data->exp_win_event_id = exp_win_event_id;
|
||||
data->exp_win_event_hwnd = exp_win_event_hwnd;
|
||||
data->exp_win_event_obj_id = exp_win_event_obj_id;
|
||||
data->exp_win_event_child_id = exp_win_event_child_id;
|
||||
}
|
||||
|
||||
static void set_provider_runtime_id(struct Provider *prov, int val, int val2)
|
||||
{
|
||||
prov->runtime_id[0] = val;
|
||||
prov->runtime_id[1] = val2;
|
||||
}
|
||||
|
||||
static void initialize_provider_advise_events_ids(struct Provider *prov)
|
||||
{
|
||||
prov->advise_events_added_event_id = prov->advise_events_removed_event_id = 0;
|
||||
}
|
||||
|
||||
static void initialize_provider(struct Provider *prov, int prov_opts, HWND hwnd, BOOL initialize_nav_links)
|
||||
{
|
||||
prov->prov_opts = prov_opts;
|
||||
|
@ -10812,6 +10959,7 @@ static void initialize_provider(struct Provider *prov, int prov_opts, HWND hwnd,
|
|||
prov->embedded_frag_roots = NULL;
|
||||
prov->embedded_frag_roots_count = 0;
|
||||
prov->advise_events_added_event_id = prov->advise_events_removed_event_id = 0;
|
||||
memset(&prov->win_event_handler_data, 0, sizeof(prov->win_event_handler_data));
|
||||
if (initialize_nav_links)
|
||||
{
|
||||
prov->frag_root = NULL;
|
||||
|
@ -11875,6 +12023,14 @@ static HWND create_child_test_hwnd(const char *class_name, HWND parent)
|
|||
0, 0, 50, 50, parent, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static void destroy_test_hwnd(HWND hwnd, const char *class_name, const char *child_class_name)
|
||||
{
|
||||
DestroyWindow(hwnd);
|
||||
UnregisterClassA(class_name, NULL);
|
||||
if (child_class_name)
|
||||
UnregisterClassA(child_class_name, NULL);
|
||||
}
|
||||
|
||||
static IUIAutomationElement *create_test_element_from_hwnd(IUIAutomation *uia_iface, HWND hwnd, BOOL block_hwnd_provs)
|
||||
{
|
||||
IUIAutomationElement *element;
|
||||
|
@ -14164,6 +14320,17 @@ static void check_uia_hwnd_expects_at_most(int proxy_cback_count, int base_hwnd_
|
|||
CHECK_CALLED_AT_MOST(winproc_GETOBJECT_CLIENT, win_get_client_obj_count);
|
||||
}
|
||||
|
||||
static void check_uia_hwnd_expects_at_least(int proxy_cback_count, BOOL proxy_cback_todo,
|
||||
int base_hwnd_cback_count, BOOL base_hwnd_cback_todo, int nc_cback_count, BOOL nc_cback_todo,
|
||||
int win_get_uia_obj_count, BOOL win_get_uia_obj_todo, int win_get_client_obj_count, BOOL win_get_client_obj_todo)
|
||||
{
|
||||
todo_wine_if(proxy_cback_todo) CHECK_CALLED_AT_LEAST(prov_callback_proxy, proxy_cback_count);
|
||||
todo_wine_if(base_hwnd_cback_todo) CHECK_CALLED_AT_LEAST(prov_callback_base_hwnd, base_hwnd_cback_count);
|
||||
todo_wine_if(nc_cback_todo) CHECK_CALLED_AT_LEAST(prov_callback_nonclient, nc_cback_count);
|
||||
todo_wine_if(win_get_uia_obj_todo) CHECK_CALLED_AT_LEAST(winproc_GETOBJECT_UiaRoot, win_get_uia_obj_count);
|
||||
todo_wine_if(win_get_client_obj_todo) CHECK_CALLED_AT_LEAST(winproc_GETOBJECT_CLIENT, win_get_client_obj_count);
|
||||
}
|
||||
|
||||
static struct ComEventData {
|
||||
struct node_provider_desc exp_node_desc;
|
||||
struct node_provider_desc exp_nested_node_desc;
|
||||
|
@ -15551,47 +15718,67 @@ static struct EventData {
|
|||
|
||||
struct node_provider_desc exp_nested_node_desc;
|
||||
HANDLE event_handle;
|
||||
} EventData;
|
||||
} EventData, EventData2;
|
||||
|
||||
static void set_event_data(LONG exp_lbound0, LONG exp_lbound1, LONG exp_elems0, LONG exp_elems1,
|
||||
struct node_provider_desc *exp_node_desc, const WCHAR *exp_tree_struct)
|
||||
static void set_event_data_struct(struct EventData *data, LONG exp_lbound0, LONG exp_lbound1, LONG exp_elems0,
|
||||
LONG exp_elems1, struct node_provider_desc *exp_node_desc, const WCHAR *exp_tree_struct)
|
||||
{
|
||||
EventData.exp_lbound[0] = exp_lbound0;
|
||||
EventData.exp_lbound[1] = exp_lbound1;
|
||||
EventData.exp_elems[0] = exp_elems0;
|
||||
EventData.exp_elems[1] = exp_elems1;
|
||||
data->exp_lbound[0] = exp_lbound0;
|
||||
data->exp_lbound[1] = exp_lbound1;
|
||||
data->exp_elems[0] = exp_elems0;
|
||||
data->exp_elems[1] = exp_elems1;
|
||||
if (exp_node_desc)
|
||||
{
|
||||
int i;
|
||||
|
||||
EventData.exp_node_desc = *exp_node_desc;
|
||||
data->exp_node_desc = *exp_node_desc;
|
||||
for (i = 0; i < exp_node_desc->prov_count; i++)
|
||||
{
|
||||
if (exp_node_desc->nested_desc[i])
|
||||
{
|
||||
EventData.exp_nested_node_desc = *exp_node_desc->nested_desc[i];
|
||||
EventData.exp_node_desc.nested_desc[i] = &EventData.exp_nested_node_desc;
|
||||
data->exp_nested_node_desc = *exp_node_desc->nested_desc[i];
|
||||
data->exp_node_desc.nested_desc[i] = &data->exp_nested_node_desc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
memset(&EventData.exp_node_desc, 0, sizeof(EventData.exp_node_desc));
|
||||
EventData.exp_tree_struct = exp_tree_struct;
|
||||
memset(&data->exp_node_desc, 0, sizeof(data->exp_node_desc));
|
||||
data->exp_tree_struct = exp_tree_struct;
|
||||
}
|
||||
|
||||
static void set_event_data(LONG exp_lbound0, LONG exp_lbound1, LONG exp_elems0, LONG exp_elems1,
|
||||
struct node_provider_desc *exp_node_desc, const WCHAR *exp_tree_struct)
|
||||
{
|
||||
set_event_data_struct(&EventData, exp_lbound0, exp_lbound1, exp_elems0, exp_elems1, exp_node_desc,
|
||||
exp_tree_struct);
|
||||
}
|
||||
|
||||
#define check_event_data( data, args, req_data, tree_struct ) \
|
||||
check_event_data_( (data), (args), (req_data), (tree_struct), __FILE__, __LINE__)
|
||||
static void check_event_data_(struct EventData *data, struct UiaEventArgs *args, SAFEARRAY *req_data, BSTR tree_struct,
|
||||
const char *file, int line)
|
||||
{
|
||||
if (!data->exp_elems[0] && !data->exp_elems[1])
|
||||
ok(!req_data, "req_data != NULL\n");
|
||||
else
|
||||
test_cache_req_sa_(req_data, data->exp_lbound, data->exp_elems, &data->exp_node_desc, file, line);
|
||||
|
||||
ok(!wcscmp(tree_struct, data->exp_tree_struct), "tree structure %s\n", debugstr_w(tree_struct));
|
||||
if (data->event_handle)
|
||||
SetEvent(data->event_handle);
|
||||
}
|
||||
|
||||
static void WINAPI uia_event_callback(struct UiaEventArgs *args, SAFEARRAY *req_data, BSTR tree_struct)
|
||||
{
|
||||
CHECK_EXPECT(uia_event_callback);
|
||||
check_event_data(&EventData, args, req_data, tree_struct);
|
||||
}
|
||||
|
||||
if (!EventData.exp_elems[0] && !EventData.exp_elems[1])
|
||||
ok(!req_data, "req_data != NULL\n");
|
||||
else
|
||||
test_cache_req_sa(req_data, EventData.exp_lbound, EventData.exp_elems, &EventData.exp_node_desc);
|
||||
|
||||
ok(!wcscmp(tree_struct, EventData.exp_tree_struct), "tree structure %s\n", debugstr_w(tree_struct));
|
||||
if (EventData.event_handle)
|
||||
SetEvent(EventData.event_handle);
|
||||
static void WINAPI uia_event_callback2(struct UiaEventArgs *args, SAFEARRAY *req_data, BSTR tree_struct)
|
||||
{
|
||||
CHECK_EXPECT(uia_event_callback2);
|
||||
check_event_data(&EventData2, args, req_data, tree_struct);
|
||||
}
|
||||
|
||||
enum {
|
||||
|
@ -16516,6 +16703,453 @@ static void test_UiaHasServerSideProvider(void)
|
|||
UnregisterClassA("UiaHasServerSideProvider test class", NULL);
|
||||
}
|
||||
|
||||
static const struct prov_method_sequence win_event_handler_seq[] = {
|
||||
{ &Provider_proxy, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, METHOD_TODO },
|
||||
{ &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 },
|
||||
{ &Provider_hwnd2, WINEVENT_HANDLER_RESPOND_TO_WINEVENT },
|
||||
NODE_CREATE_SEQ(&Provider_child),
|
||||
{ &Provider_child, FRAG_GET_RUNTIME_ID },
|
||||
{ &Provider_child, PROV_GET_PROPERTY_VALUE }, /* UIA_ProviderDescriptionPropertyId */
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
#define test_uia_event_win_event_mapping( win_event, hwnd, obj_id, child_id, event_handles, event_handle_count, \
|
||||
expect_event1, expect_event2, todo ) \
|
||||
test_uia_event_win_event_mapping_( (win_event), (hwnd), (obj_id), (child_id), (event_handles), (event_handle_count), \
|
||||
(expect_event1), (expect_event2), (todo), __FILE__, __LINE__)
|
||||
static void test_uia_event_win_event_mapping_(DWORD win_event, HWND hwnd, LONG obj_id, LONG child_id,
|
||||
HANDLE *event_handles, int event_handle_count, BOOL expect_event1, BOOL expect_event2,
|
||||
BOOL todo, const char *file, int line)
|
||||
{
|
||||
const BOOL exp_timeout = (!expect_event1 && !expect_event2);
|
||||
DWORD timeout_val = exp_timeout ? 500 : 3000;
|
||||
DWORD wait_res;
|
||||
|
||||
SET_EXPECT_MULTI(uia_event_callback, !!expect_event1);
|
||||
SET_EXPECT_MULTI(uia_event_callback2, !!expect_event2);
|
||||
if (expect_event2)
|
||||
SET_EXPECT(uia_event_callback2);
|
||||
NotifyWinEvent(win_event, hwnd, obj_id, child_id);
|
||||
|
||||
wait_res = msg_wait_for_all_events(event_handles, event_handle_count, timeout_val);
|
||||
todo_wine_if(todo) ok_(file, line)((wait_res == WAIT_TIMEOUT) == exp_timeout,
|
||||
"Unexpected result while waiting for event callback(s).\n");
|
||||
if (expect_event1)
|
||||
todo_wine_if(todo) CHECK_CALLED(uia_event_callback);
|
||||
if (expect_event2)
|
||||
todo_wine_if(todo) CHECK_CALLED(uia_event_callback2);
|
||||
}
|
||||
|
||||
#define test_provider_event_advise_added( prov, event_id, todo) \
|
||||
test_provider_event_advise_added_( (prov), (event_id), (todo), __FILE__, __LINE__)
|
||||
static void test_provider_event_advise_added_(struct Provider *prov, int event_id, BOOL todo, const char *file, int line)
|
||||
{
|
||||
todo_wine_if (todo) ok_(file, line)(prov->advise_events_added_event_id == event_id, "%s: Unexpected advise event added, event ID %d.\n",
|
||||
prov->prov_name, prov->advise_events_added_event_id);
|
||||
}
|
||||
|
||||
static DWORD WINAPI uia_proxy_provider_win_event_handler_test_thread(LPVOID param)
|
||||
{
|
||||
struct UiaCacheRequest cache_req = { (struct UiaCondition *)&UiaTrueCondition, TreeScope_Element, NULL, 0, NULL, 0,
|
||||
AutomationElementMode_Full };
|
||||
HWND hwnd[2] = { ((HWND *)param)[0], ((HWND *)param)[1] };
|
||||
struct node_provider_desc exp_node_desc;
|
||||
HUIAEVENT event, event2;
|
||||
HANDLE event_handles[2];
|
||||
HWND tmp_hwnd;
|
||||
HUIANODE node;
|
||||
HRESULT hr;
|
||||
int i;
|
||||
|
||||
method_sequences_enabled = FALSE;
|
||||
CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
||||
for (i = 0; i < ARRAY_SIZE(event_handles); i++)
|
||||
event_handles[i] = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||
|
||||
set_uia_hwnd_expects(1, 1, 1, 2, 0);
|
||||
hr = UiaNodeFromHandle(hwnd[0], &node);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
ok(!!node, "Node == NULL.\n");
|
||||
check_uia_hwnd_expects_at_most(1, 1, 1, 2, 0);
|
||||
|
||||
set_uia_hwnd_expects(2, 2, 2, 4, 0);
|
||||
hr = UiaAddEvent(node, UIA_AutomationFocusChangedEventId, uia_event_callback, TreeScope_Element, NULL, 0, &cache_req,
|
||||
&event);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
/* Windows 11 recreates HWND clientside providers for the node passed into UiaAddEvent. */
|
||||
check_uia_hwnd_expects_at_most(2, 2, 2, 4, 0);
|
||||
|
||||
set_uia_hwnd_expects(2, 2, 2, 4, 0);
|
||||
hr = UiaAddEvent(node, UIA_AutomationFocusChangedEventId, uia_event_callback2, TreeScope_Subtree, NULL, 0, &cache_req,
|
||||
&event2);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
/* Windows 11 recreates HWND clientside providers for the node passed into UiaAddEvent. */
|
||||
check_uia_hwnd_expects_at_most(2, 2, 2, 4, 0);
|
||||
UiaNodeRelease(node);
|
||||
|
||||
/*
|
||||
* Raise EVENT_OBJECT_FOCUS. If none of our clientside providers returned
|
||||
* an IProxyProviderWinEventHandler interface when being advised of events
|
||||
* being listened for, nothing happens.
|
||||
*/
|
||||
EventData.event_handle = event_handles[0];
|
||||
EventData2.event_handle = event_handles[1];
|
||||
test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, hwnd[0], OBJID_WINDOW, CHILDID_SELF, event_handles,
|
||||
ARRAY_SIZE(event_handles), FALSE, FALSE, FALSE);
|
||||
|
||||
/*
|
||||
* Return an IProxyProviderWinEventHandler interface on our clientside
|
||||
* providers. WinEvents will now be listened for. If a provider returns a
|
||||
* WinEvent handler interface, IRawElementProviderAdviseEvents will not be
|
||||
* queried for or used.
|
||||
*/
|
||||
initialize_provider_advise_events_ids(&Provider_hwnd2);
|
||||
initialize_provider_advise_events_ids(&Provider_nc2);
|
||||
Provider_hwnd2.win_event_handler_data.is_supported = Provider_nc2.win_event_handler_data.is_supported = TRUE;
|
||||
set_uia_hwnd_expects(1, 1, 1, 2, 0);
|
||||
hr = UiaEventAddWindow(event, hwnd[0]);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
test_provider_event_advise_added(&Provider_hwnd2, 0, TRUE);
|
||||
test_provider_event_advise_added(&Provider_nc2, 0, TRUE);
|
||||
check_uia_hwnd_expects_at_least(1, TRUE, 1, FALSE, 1, FALSE, 1, FALSE, 0, FALSE);
|
||||
|
||||
/*
|
||||
* WinEvents will now be listened for, however if our HWND has a
|
||||
* serverside provider they will be ignored.
|
||||
*/
|
||||
SET_EXPECT_MULTI(winproc_GETOBJECT_UiaRoot, 2); /* Only called twice on Win11. */
|
||||
test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, hwnd[0], OBJID_WINDOW, CHILDID_SELF, event_handles,
|
||||
1, FALSE, FALSE, FALSE);
|
||||
todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
|
||||
|
||||
/*
|
||||
* Get rid of our serverside provider and raise EVENT_OBJECT_FOCUS
|
||||
* again. Now, our WinEvent handler interfaces will be invoked.
|
||||
*/
|
||||
prov_root = NULL;
|
||||
set_provider_win_event_handler_win_event_expects(&Provider_hwnd2, EVENT_OBJECT_FOCUS, hwnd[0], OBJID_WINDOW, CHILDID_SELF);
|
||||
set_provider_win_event_handler_win_event_expects(&Provider_nc2, EVENT_OBJECT_FOCUS, hwnd[0], OBJID_WINDOW, CHILDID_SELF);
|
||||
|
||||
initialize_provider(&Provider_child, ProviderOptions_ServerSideProvider, NULL, TRUE);
|
||||
set_provider_runtime_id(&Provider_child, UIA_RUNTIME_ID_PREFIX, HandleToUlong(hwnd[0]));
|
||||
set_provider_win_event_handler_respond_prov(&Provider_hwnd2, &Provider_child.IRawElementProviderSimple_iface,
|
||||
UIA_AutomationFocusChangedEventId);
|
||||
|
||||
init_node_provider_desc(&exp_node_desc, GetCurrentProcessId(), NULL);
|
||||
add_provider_desc(&exp_node_desc, L"Main", L"Provider_child", TRUE);
|
||||
set_event_data(0, 0, 1, 1, &exp_node_desc, L"P)");
|
||||
|
||||
method_sequences_enabled = TRUE;
|
||||
set_uia_hwnd_expects(1, 1, 1, 4, 3);
|
||||
test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, hwnd[0], OBJID_WINDOW, CHILDID_SELF, event_handles,
|
||||
1, TRUE, FALSE, TRUE);
|
||||
if (CALLED_COUNT(winproc_GETOBJECT_CLIENT))
|
||||
ok_method_sequence(win_event_handler_seq, "win_event_handler_seq");
|
||||
check_uia_hwnd_expects_at_least(1, TRUE, 1, TRUE, 1, TRUE, 1, TRUE, 1, TRUE);
|
||||
method_sequences_enabled = FALSE;
|
||||
|
||||
/*
|
||||
* Not all WinEvents are passed to our WinEvent responder interface -
|
||||
* they're filtered by HWND.
|
||||
*/
|
||||
Provider_hwnd.win_event_handler_data.is_supported = Provider_nc.win_event_handler_data.is_supported = TRUE;
|
||||
set_provider_win_event_handler_win_event_expects(&Provider_nc, EVENT_OBJECT_FOCUS, GetDesktopWindow(), OBJID_WINDOW, CHILDID_SELF);
|
||||
set_provider_win_event_handler_respond_prov(&Provider_nc, &Provider_child.IRawElementProviderSimple_iface,
|
||||
UIA_AutomationFocusChangedEventId);
|
||||
SET_EXPECT(uia_event_callback);
|
||||
set_uia_hwnd_expects(0, 1, 1, 0, 0);
|
||||
NotifyWinEvent(EVENT_OBJECT_FOCUS, GetDesktopWindow(), OBJID_WINDOW, CHILDID_SELF);
|
||||
if (msg_wait_for_all_events(event_handles, 1, 3000) == WAIT_OBJECT_0)
|
||||
{
|
||||
win_skip("Win10v1507 and below don't filter WinEvents by HWND, skipping further tests.\n");
|
||||
|
||||
CHECK_CALLED(uia_event_callback);
|
||||
check_uia_hwnd_expects(0, FALSE, 1, FALSE, 1, FALSE, 0, FALSE, 0, FALSE);
|
||||
hr = UiaRemoveEvent(event);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
|
||||
hr = UiaRemoveEvent(event2);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
goto skip_win_event_hwnd_filter_test;
|
||||
}
|
||||
|
||||
/* Clear expects/called values. */
|
||||
CHECK_CALLED_MULTI(uia_event_callback, 0);
|
||||
|
||||
/*
|
||||
* Child HWNDs of top level HWNDs that are within our scope are listened
|
||||
* to by default.
|
||||
*/
|
||||
child_win_prov_root = NULL;
|
||||
Provider_hwnd3.win_event_handler_data.is_supported = Provider_nc3.win_event_handler_data.is_supported = TRUE;
|
||||
set_provider_win_event_handler_win_event_expects(&Provider_nc3, EVENT_OBJECT_FOCUS, hwnd[1], OBJID_WINDOW, CHILDID_SELF);
|
||||
set_provider_win_event_handler_win_event_expects(&Provider_hwnd3, EVENT_OBJECT_FOCUS, hwnd[1], OBJID_WINDOW, CHILDID_SELF);
|
||||
set_provider_win_event_handler_respond_prov(&Provider_nc3, &Provider_child.IRawElementProviderSimple_iface,
|
||||
UIA_AutomationFocusChangedEventId);
|
||||
|
||||
set_uia_hwnd_expects(0, 1, 1, 2, 0);
|
||||
SET_EXPECT_MULTI(child_winproc_GETOBJECT_UiaRoot, 4); /* Only sent 4 times on Win11. */
|
||||
test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, hwnd[1], OBJID_WINDOW, CHILDID_SELF, event_handles,
|
||||
1, TRUE, FALSE, TRUE);
|
||||
check_uia_hwnd_expects_at_least(0, FALSE, 1, TRUE, 1, TRUE, 1, TRUE, 0, FALSE);
|
||||
todo_wine CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot);
|
||||
|
||||
/*
|
||||
* Child HWND now has a serverside provider, WinEvent is ignored.
|
||||
*/
|
||||
child_win_prov_root = &Provider2.IRawElementProviderSimple_iface;
|
||||
|
||||
SET_EXPECT(winproc_GETOBJECT_UiaRoot); /* Only sent on Win11. */
|
||||
SET_EXPECT_MULTI(child_winproc_GETOBJECT_UiaRoot, 2); /* Only sent 2 times on Win11. */
|
||||
test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, hwnd[1], OBJID_WINDOW, CHILDID_SELF, event_handles,
|
||||
1, FALSE, FALSE, FALSE);
|
||||
todo_wine CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot);
|
||||
CHECK_CALLED_AT_MOST(winproc_GETOBJECT_UiaRoot, 1);
|
||||
|
||||
/*
|
||||
* HWNDs owned by a top level HWND that is within our scope are ignored.
|
||||
*/
|
||||
child_win_prov_root = NULL;
|
||||
tmp_hwnd = CreateWindowA("ProxyProviderWinEventHandler test child class", "Test child window 2", WS_POPUP,
|
||||
0, 0, 50, 50, hwnd[0], NULL, NULL, NULL);
|
||||
Provider_nc3.hwnd = Provider_hwnd3.hwnd = tmp_hwnd;
|
||||
test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, tmp_hwnd, OBJID_WINDOW, CHILDID_SELF, event_handles,
|
||||
1, FALSE, FALSE, FALSE);
|
||||
DestroyWindow(tmp_hwnd);
|
||||
|
||||
/*
|
||||
* Add our test child HWND to event2. This only puts the child HWND within
|
||||
* the scope of event2, it doesn't put the parent HWND within its scope.
|
||||
*/
|
||||
child_win_prov_root = &Provider2.IRawElementProviderSimple_iface;
|
||||
Provider_nc3.hwnd = Provider_hwnd3.hwnd = hwnd[1];
|
||||
SET_EXPECT_MULTI(child_winproc_GETOBJECT_UiaRoot, 2); /* Only sent 2 times on Win11. */
|
||||
set_uia_hwnd_expects(0, 1, 1, 1, 0);
|
||||
hr = UiaEventAddWindow(event2, hwnd[1]);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
check_uia_hwnd_expects_at_least(0, FALSE, 1, FALSE, 1, FALSE, 1, TRUE, 0, FALSE);
|
||||
CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot);
|
||||
|
||||
/*
|
||||
* Raise a WinEvent on our top level test HWND, will not invoke the
|
||||
* callback on event2.
|
||||
*/
|
||||
set_uia_hwnd_expects(1, 1, 1, 4, 3);
|
||||
test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, hwnd[0], OBJID_WINDOW, CHILDID_SELF, event_handles,
|
||||
1, TRUE, FALSE, TRUE);
|
||||
check_uia_hwnd_expects_at_least(1, TRUE, 1, TRUE, 1, TRUE, 1, TRUE, 1, TRUE);
|
||||
|
||||
/* Raise a WinEvent on our test child HWND, both event callbacks invoked. */
|
||||
child_win_prov_root = NULL;
|
||||
set_event_data_struct(&EventData2, 0, 0, 1, 1, &exp_node_desc, L"P)");
|
||||
|
||||
set_uia_hwnd_expects(0, 2, 2, 4, 0);
|
||||
SET_EXPECT_MULTI(child_winproc_GETOBJECT_UiaRoot, 8); /* Only sent 8 times on Win11. */
|
||||
test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, hwnd[1], OBJID_WINDOW, CHILDID_SELF, event_handles,
|
||||
ARRAY_SIZE(event_handles), TRUE, TRUE, TRUE);
|
||||
todo_wine CHECK_CALLED_AT_LEAST(child_winproc_GETOBJECT_UiaRoot, 2);
|
||||
check_uia_hwnd_expects_at_least(0, FALSE, 2, TRUE, 2, TRUE, 2, TRUE, 0, FALSE);
|
||||
|
||||
hr = UiaRemoveEvent(event);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
|
||||
hr = UiaRemoveEvent(event2);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
|
||||
/*
|
||||
* Create an event on the desktop HWND. If a WinEvent handler interface is
|
||||
* returned on a provider representing the desktop HWND, all visible
|
||||
* top-level HWNDs at the time of advisement will be considered within
|
||||
* scope.
|
||||
*/
|
||||
set_uia_hwnd_expects(1, 1, 1, 0, 0);
|
||||
hr = UiaGetRootNode(&node);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
ok(!!node, "Node == NULL.\n");
|
||||
check_uia_hwnd_expects(1, FALSE, 1, FALSE, 1, FALSE, 0, FALSE, 0, FALSE);
|
||||
|
||||
Provider_proxy.win_event_handler_data.is_supported = TRUE;
|
||||
Provider_hwnd.win_event_handler_data.is_supported = Provider_nc.win_event_handler_data.is_supported = TRUE;
|
||||
set_provider_win_event_handler_win_event_expects(&Provider_nc, EVENT_OBJECT_FOCUS, GetDesktopWindow(), OBJID_WINDOW, CHILDID_SELF);
|
||||
set_provider_win_event_handler_win_event_expects(&Provider_hwnd, EVENT_OBJECT_FOCUS, GetDesktopWindow(), OBJID_WINDOW, CHILDID_SELF);
|
||||
set_provider_win_event_handler_respond_prov(&Provider_nc, &Provider_child.IRawElementProviderSimple_iface,
|
||||
UIA_AutomationFocusChangedEventId);
|
||||
|
||||
/* Register a focus change event handler on the desktop HWND. */
|
||||
hr = UiaAddEvent(node, UIA_AutomationFocusChangedEventId, uia_event_callback, TreeScope_Element, NULL, 0, &cache_req,
|
||||
&event);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
test_provider_event_advise_added(&Provider_proxy, 0, TRUE);
|
||||
test_provider_event_advise_added(&Provider_hwnd, 0, TRUE);
|
||||
test_provider_event_advise_added(&Provider_nc, 0, TRUE);
|
||||
|
||||
/* Raise WinEvent on the desktop HWND. */
|
||||
set_provider_runtime_id(&Provider_child, UIA_RUNTIME_ID_PREFIX, HandleToUlong(GetDesktopWindow()));
|
||||
set_provider_win_event_handler_respond_prov(&Provider_hwnd, &Provider_child.IRawElementProviderSimple_iface,
|
||||
UIA_AutomationFocusChangedEventId);
|
||||
set_uia_hwnd_expects(0, 1, 1, 0, 0);
|
||||
test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, GetDesktopWindow(), OBJID_WINDOW, CHILDID_SELF, event_handles,
|
||||
1, TRUE, FALSE, TRUE);
|
||||
check_uia_hwnd_expects(0, FALSE, 1, TRUE, 1, TRUE, 0, FALSE, 0, FALSE);
|
||||
|
||||
/*
|
||||
* Top-level HWND, a child of the desktop HWND. Will not have an event
|
||||
* raised since it was not visible when the desktop providers were advised
|
||||
* of an event being added.
|
||||
*/
|
||||
test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, hwnd[0], OBJID_WINDOW, CHILDID_SELF, event_handles,
|
||||
1, FALSE, FALSE, FALSE);
|
||||
|
||||
/* Test child hwnd, same deal. */
|
||||
test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, hwnd[1], OBJID_WINDOW, CHILDID_SELF, event_handles,
|
||||
1, FALSE, FALSE, FALSE);
|
||||
|
||||
/*
|
||||
* Show window after calling UiaAddEvent(), does nothing. Window must be
|
||||
* visible when provider is advised of an event being added.
|
||||
*/
|
||||
ShowWindow(hwnd[0], SW_SHOW);
|
||||
test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, hwnd[0], OBJID_WINDOW, CHILDID_SELF, event_handles,
|
||||
1, FALSE, FALSE, FALSE);
|
||||
|
||||
hr = UiaRemoveEvent(event);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
|
||||
/*
|
||||
* Create the event again, except this time our test HWND was visible when
|
||||
* the desktop provider was advised that our event was being added. Now
|
||||
* WinEvents on our test HWND will be handled.
|
||||
*/
|
||||
hr = UiaAddEvent(node, UIA_AutomationFocusChangedEventId, uia_event_callback, TreeScope_Element, NULL, 0, &cache_req,
|
||||
&event);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
test_provider_event_advise_added(&Provider_hwnd, 0, TRUE);
|
||||
test_provider_event_advise_added(&Provider_nc, 0, TRUE);
|
||||
test_provider_event_advise_added(&Provider_proxy, 0, TRUE);
|
||||
|
||||
/* WinEvent handled. */
|
||||
set_uia_hwnd_expects(1, 1, 1, 2, 1);
|
||||
test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, hwnd[0], OBJID_WINDOW, CHILDID_SELF, event_handles,
|
||||
1, TRUE, FALSE, TRUE);
|
||||
check_uia_hwnd_expects(1, TRUE, 1, TRUE, 1, TRUE, 2, TRUE, 1, TRUE);
|
||||
|
||||
/* Child HWNDs of our test window are handled as well. */
|
||||
SET_EXPECT_MULTI(child_winproc_GETOBJECT_UiaRoot, 2);
|
||||
set_uia_hwnd_expects(0, 1, 1, 1, 0);
|
||||
test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, hwnd[1], OBJID_WINDOW, CHILDID_SELF, event_handles,
|
||||
1, TRUE, FALSE, TRUE);
|
||||
check_uia_hwnd_expects(0, FALSE, 1, TRUE, 1, TRUE, 1, TRUE, 0, FALSE);
|
||||
|
||||
hr = UiaRemoveEvent(event);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
|
||||
UiaNodeRelease(node);
|
||||
|
||||
skip_win_event_hwnd_filter_test:
|
||||
/*
|
||||
* Test default MSAA proxy WinEvent handler.
|
||||
*/
|
||||
prov_root = &Provider.IRawElementProviderSimple_iface;
|
||||
set_uia_hwnd_expects(2, 1, 1, 2, 0);
|
||||
hr = UiaNodeFromHandle(hwnd[0], &node);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
ok(!!node, "Node == NULL.\n");
|
||||
check_uia_hwnd_expects_at_most(1, 1, 1, 2, 0);
|
||||
|
||||
Provider_hwnd2.win_event_handler_data.is_supported = Provider_nc2.win_event_handler_data.is_supported = TRUE;
|
||||
hr = UiaAddEvent(node, UIA_SystemAlertEventId, uia_event_callback, TreeScope_Subtree, NULL, 0, &cache_req,
|
||||
&event);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
UiaNodeRelease(node);
|
||||
|
||||
set_provider_win_event_handler_respond_prov(&Provider_hwnd2, NULL, 0);
|
||||
set_provider_win_event_handler_win_event_expects(&Provider_hwnd2, 0, hwnd[0], 0, 0);
|
||||
set_provider_win_event_handler_respond_prov(&Provider_nc2, NULL, 0);
|
||||
set_provider_win_event_handler_win_event_expects(&Provider_nc2, 0, NULL, 0, 0);
|
||||
|
||||
prov_root = NULL;
|
||||
init_node_provider_desc(&exp_node_desc, GetCurrentProcessId(), NULL);
|
||||
add_provider_desc(&exp_node_desc, L"Main", NULL, TRUE); /* MSAA proxy. */
|
||||
set_event_data(0, 0, 1, 1, &exp_node_desc, L"P)");
|
||||
|
||||
/* WinEvent handled by default MSAA proxy provider. */
|
||||
set_uia_hwnd_expects(1, 1, 1, 4, 5);
|
||||
test_uia_event_win_event_mapping(EVENT_SYSTEM_ALERT, hwnd[0], OBJID_CLIENT, 2, event_handles,
|
||||
1, TRUE, FALSE, TRUE);
|
||||
check_uia_hwnd_expects_at_most(1, 1, 1, 4, 5);
|
||||
|
||||
hr = UiaRemoveEvent(event);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(event_handles); i++)
|
||||
CloseHandle(event_handles[i]);
|
||||
method_sequences_enabled = TRUE;
|
||||
CoUninitialize();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_uia_event_ProxyProviderWinEventHandler(void)
|
||||
{
|
||||
HANDLE thread;
|
||||
HWND hwnd[2];
|
||||
|
||||
/*
|
||||
* Windows 7 behaves different than all other versions, just skip the
|
||||
* tests.
|
||||
*/
|
||||
if (!UiaLookupId(AutomationIdentifierType_Property, &OptimizeForVisualContent_Property_GUID))
|
||||
{
|
||||
win_skip("Skipping IProxyProviderWinEventSink tests for Win7\n");
|
||||
return;
|
||||
}
|
||||
|
||||
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
||||
|
||||
hwnd[0] = create_test_hwnd("ProxyProviderWinEventHandler test class");
|
||||
hwnd[1] = create_child_test_hwnd("ProxyProviderWinEventHandler test child class", hwnd[0]);
|
||||
|
||||
UiaRegisterProviderCallback(test_uia_provider_callback);
|
||||
|
||||
/* Set clientside providers for our test windows and the desktop. */
|
||||
set_clientside_providers_for_hwnd(&Provider_proxy, &Provider_nc, &Provider_hwnd, GetDesktopWindow());
|
||||
base_hwnd_prov = &Provider_hwnd.IRawElementProviderSimple_iface;
|
||||
nc_prov = &Provider_nc.IRawElementProviderSimple_iface;
|
||||
proxy_prov = &Provider_proxy.IRawElementProviderSimple_iface;
|
||||
|
||||
set_clientside_providers_for_hwnd(NULL, &Provider_nc2, &Provider_hwnd2, hwnd[0]);
|
||||
initialize_provider(&Provider, ProviderOptions_ServerSideProvider, hwnd[0], TRUE);
|
||||
Provider.frag_root = &Provider.IRawElementProviderFragmentRoot_iface;
|
||||
Provider.ignore_hwnd_prop = TRUE;
|
||||
|
||||
set_clientside_providers_for_hwnd(NULL, &Provider_nc3, &Provider_hwnd3, hwnd[1]);
|
||||
initialize_provider(&Provider2, ProviderOptions_ServerSideProvider, hwnd[1], TRUE);
|
||||
Provider2.frag_root = &Provider2.IRawElementProviderFragmentRoot_iface;
|
||||
Provider2.ignore_hwnd_prop = TRUE;
|
||||
|
||||
prov_root = &Provider.IRawElementProviderSimple_iface;
|
||||
child_win_prov_root = &Provider2.IRawElementProviderSimple_iface;
|
||||
|
||||
thread = CreateThread(NULL, 0, uia_proxy_provider_win_event_handler_test_thread, (void *)hwnd, 0, NULL);
|
||||
while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_ALLINPUT) != WAIT_OBJECT_0)
|
||||
{
|
||||
MSG msg;
|
||||
|
||||
while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessageW(&msg);
|
||||
}
|
||||
}
|
||||
CloseHandle(thread);
|
||||
|
||||
CoUninitialize();
|
||||
destroy_test_hwnd(hwnd[0], "ProxyProviderWinEventHandler test class", "ProxyProviderWinEventHandler test child class");
|
||||
UiaRegisterProviderCallback(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Once a process returns a UI Automation provider with
|
||||
* UiaReturnRawElementProvider it ends up in an implicit MTA until exit. This
|
||||
|
@ -16590,6 +17224,7 @@ START_TEST(uiautomation)
|
|||
test_UiaNodeFromFocus();
|
||||
test_UiaAddEvent(argv[0]);
|
||||
test_UiaHasServerSideProvider();
|
||||
test_uia_event_ProxyProviderWinEventHandler();
|
||||
if (uia_dll)
|
||||
{
|
||||
pUiaProviderFromIAccessible = (void *)GetProcAddress(uia_dll, "UiaProviderFromIAccessible");
|
||||
|
|
Loading…
Add table
Reference in a new issue