uiautomationcore/tests: Add tests for COM event handler event advisement.
Signed-off-by: Connor McAdams <cmcadams@codeweavers.com>
This commit is contained in:
parent
8a571b263b
commit
f420b65a82
1 changed files with 373 additions and 11 deletions
|
@ -1640,6 +1640,8 @@ static struct Provider
|
|||
int advise_events_added_event_id;
|
||||
int advise_events_removed_event_id;
|
||||
struct Provider_win_event_handler_data win_event_handler_data;
|
||||
HANDLE method_call_event_handle;
|
||||
int method_call_event_method_id;
|
||||
} 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);
|
||||
|
@ -1910,6 +1912,12 @@ static void ok_method_sequence_(const struct prov_method_sequence *expected_list
|
|||
flush_method_sequence();
|
||||
}
|
||||
|
||||
static void check_for_method_call_event(struct Provider *prov, int method)
|
||||
{
|
||||
if (prov->method_call_event_handle && (prov->method_call_event_method_id == method))
|
||||
SetEvent(prov->method_call_event_handle);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parsing the string returned by UIA_ProviderDescriptionPropertyId is
|
||||
* the only way to know what an HUIANODE represents internally. It
|
||||
|
@ -2142,6 +2150,7 @@ HRESULT WINAPI ProviderSimple_get_ProviderOptions(IRawElementProviderSimple *ifa
|
|||
if (This->expected_tid)
|
||||
ok(This->expected_tid == GetCurrentThreadId(), "Unexpected tid %ld\n", GetCurrentThreadId());
|
||||
This->last_call_tid = GetCurrentThreadId();
|
||||
check_for_method_call_event(This, PROV_GET_PROVIDER_OPTIONS);
|
||||
PROV_METHOD_TRACE(This, get_ProviderOptions);
|
||||
|
||||
*ret_val = 0;
|
||||
|
@ -2185,6 +2194,7 @@ HRESULT WINAPI ProviderSimple_GetPatternProvider(IRawElementProviderSimple *ifac
|
|||
if (*ret_val)
|
||||
IUnknown_AddRef(*ret_val);
|
||||
|
||||
check_for_method_call_event(This, PROV_GET_PATTERN_PROV);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -2197,6 +2207,7 @@ HRESULT WINAPI ProviderSimple_GetPropertyValue(IRawElementProviderSimple *iface,
|
|||
if (This->expected_tid)
|
||||
ok(This->expected_tid == GetCurrentThreadId(), "Unexpected tid %ld\n", GetCurrentThreadId());
|
||||
This->last_call_tid = GetCurrentThreadId();
|
||||
check_for_method_call_event(This, PROV_GET_PROPERTY_VALUE);
|
||||
PROV_METHOD_TRACE2(This, GetPropertyValue, prop_id, uia_prop_id_strs);
|
||||
|
||||
if (This->prop_override && This->prop_override_count)
|
||||
|
@ -2405,6 +2416,7 @@ HRESULT WINAPI ProviderSimple_get_HostRawElementProvider(IRawElementProviderSimp
|
|||
if (This->expected_tid)
|
||||
ok(This->expected_tid == GetCurrentThreadId(), "Unexpected tid %ld\n", GetCurrentThreadId());
|
||||
This->last_call_tid = GetCurrentThreadId();
|
||||
check_for_method_call_event(This, PROV_GET_HOST_RAW_ELEMENT_PROVIDER);
|
||||
PROV_METHOD_TRACE(This, get_HostRawElementProvider);
|
||||
|
||||
*ret_val = NULL;
|
||||
|
@ -2490,6 +2502,7 @@ static HRESULT WINAPI ProviderFragment_Navigate(IRawElementProviderFragment *ifa
|
|||
if (*ret_val)
|
||||
IRawElementProviderFragment_AddRef(*ret_val);
|
||||
|
||||
check_for_method_call_event(This, FRAG_NAVIGATE);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -2502,6 +2515,7 @@ static HRESULT WINAPI ProviderFragment_GetRuntimeId(IRawElementProviderFragment
|
|||
if (This->expected_tid)
|
||||
ok(This->expected_tid == GetCurrentThreadId(), "Unexpected tid %ld\n", GetCurrentThreadId());
|
||||
This->last_call_tid = GetCurrentThreadId();
|
||||
check_for_method_call_event(This, FRAG_GET_RUNTIME_ID);
|
||||
PROV_METHOD_TRACE(This, GetRuntimeId);
|
||||
|
||||
*ret_val = NULL;
|
||||
|
@ -2531,6 +2545,7 @@ static HRESULT WINAPI ProviderFragment_get_BoundingRectangle(IRawElementProvider
|
|||
if (This->expected_tid)
|
||||
ok(This->expected_tid == GetCurrentThreadId(), "Unexpected tid %ld\n", GetCurrentThreadId());
|
||||
This->last_call_tid = GetCurrentThreadId();
|
||||
check_for_method_call_event(This, FRAG_GET_BOUNDING_RECT);
|
||||
PROV_METHOD_TRACE(This, get_BoundingRectangle);
|
||||
|
||||
*ret_val = This->bounds_rect;
|
||||
|
@ -2546,6 +2561,7 @@ static HRESULT WINAPI ProviderFragment_GetEmbeddedFragmentRoots(IRawElementProvi
|
|||
if (This->expected_tid)
|
||||
ok(This->expected_tid == GetCurrentThreadId(), "Unexpected tid %ld\n", GetCurrentThreadId());
|
||||
This->last_call_tid = GetCurrentThreadId();
|
||||
check_for_method_call_event(This, FRAG_GET_EMBEDDED_FRAGMENT_ROOTS);
|
||||
PROV_METHOD_TRACE(This, GetEmbeddedFragmentRoots);
|
||||
|
||||
*ret_val = NULL;
|
||||
|
@ -2590,6 +2606,7 @@ static HRESULT WINAPI ProviderFragment_get_FragmentRoot(IRawElementProviderFragm
|
|||
IRawElementProviderFragmentRoot_AddRef(This->frag_root);
|
||||
}
|
||||
|
||||
check_for_method_call_event(This, FRAG_GET_FRAGMENT_ROOT);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -2654,6 +2671,7 @@ static HRESULT WINAPI ProviderFragmentRoot_GetFocus(IRawElementProviderFragmentR
|
|||
IRawElementProviderFragment_AddRef(*ret_val);
|
||||
}
|
||||
|
||||
check_for_method_call_event(Provider, FRAG_ROOT_GET_FOCUS);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -2695,6 +2713,7 @@ static HRESULT WINAPI ProviderHwndOverride_GetOverrideProviderForHwnd(IRawElemen
|
|||
struct Provider *This = impl_from_ProviderHwndOverride(iface);
|
||||
|
||||
add_method_call(This, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER);
|
||||
check_for_method_call_event(This, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER);
|
||||
PROV_METHOD_TRACE(This, GetOverrideProviderForHwnd);
|
||||
|
||||
*ret_val = NULL;
|
||||
|
@ -2750,6 +2769,7 @@ static HRESULT WINAPI ProviderAdviseEvents_AdviseEventAdded(IRawElementProviderA
|
|||
This->advise_events_added_event_id = event_id;
|
||||
PROV_METHOD_TRACE2(This, AdviseEventAdded, event_id, uia_event_id_strs);
|
||||
|
||||
check_for_method_call_event(This, ADVISE_EVENTS_EVENT_ADDED);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -2765,6 +2785,7 @@ static HRESULT WINAPI ProviderAdviseEvents_AdviseEventRemoved(IRawElementProvide
|
|||
This->advise_events_removed_event_id = event_id;
|
||||
PROV_METHOD_TRACE2(This, AdviseEventRemoved, event_id, uia_event_id_strs);
|
||||
|
||||
check_for_method_call_event(This, ADVISE_EVENTS_EVENT_REMOVED);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -2829,6 +2850,7 @@ static HRESULT WINAPI ProviderWinEventHandler_RespondToWinEvent(IProxyProviderWi
|
|||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
}
|
||||
|
||||
check_for_method_call_event(This, WINEVENT_HANDLER_RESPOND_TO_WINEVENT);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -8701,6 +8723,21 @@ static const struct prov_method_sequence reg_prov_cb13[] = {
|
|||
{ 0 }
|
||||
};
|
||||
|
||||
static SAFEARRAY *get_safearray_for_elprov(IRawElementProviderSimple *elprov)
|
||||
{
|
||||
SAFEARRAY *sa = NULL;
|
||||
LONG idx = 0;
|
||||
|
||||
if (elprov)
|
||||
{
|
||||
sa = SafeArrayCreateVector(VT_UNKNOWN, 0, 1);
|
||||
if (sa)
|
||||
SafeArrayPutElement(sa, &idx, (void *)elprov);
|
||||
}
|
||||
|
||||
return sa;
|
||||
}
|
||||
|
||||
static IRawElementProviderSimple *base_hwnd_prov, *proxy_prov, *parent_proxy_prov, *nc_prov;
|
||||
static SAFEARRAY WINAPI *test_uia_provider_callback(HWND hwnd, enum ProviderType prov_type)
|
||||
{
|
||||
|
@ -8745,19 +8782,54 @@ static SAFEARRAY WINAPI *test_uia_provider_callback(HWND hwnd, enum ProviderType
|
|||
break;
|
||||
}
|
||||
|
||||
if (elprov)
|
||||
return get_safearray_for_elprov(elprov);
|
||||
}
|
||||
|
||||
/*
|
||||
* Same deal as test_uia_provider_callback, except we only return a provider
|
||||
* if we can match one by HWND. This is necessary due to certain versions of
|
||||
* Windows 10 unpredictably attempting to create elements in the background.
|
||||
*/
|
||||
static SAFEARRAY WINAPI *uia_com_win_event_clientside_provider_callback(HWND hwnd, enum ProviderType prov_type)
|
||||
{
|
||||
IRawElementProviderSimple *elprov = NULL;
|
||||
|
||||
switch (prov_type)
|
||||
{
|
||||
SAFEARRAY *sa;
|
||||
LONG idx = 0;
|
||||
case ProviderType_BaseHwnd:
|
||||
if (hwnd == Provider_hwnd3.hwnd)
|
||||
elprov = &Provider_hwnd3.IRawElementProviderSimple_iface;
|
||||
else if (hwnd == Provider_hwnd2.hwnd)
|
||||
elprov = &Provider_hwnd2.IRawElementProviderSimple_iface;
|
||||
else if (hwnd == Provider_hwnd.hwnd)
|
||||
elprov = &Provider_hwnd.IRawElementProviderSimple_iface;
|
||||
|
||||
sa = SafeArrayCreateVector(VT_UNKNOWN, 0, 1);
|
||||
if (sa)
|
||||
SafeArrayPutElement(sa, &idx, (void *)elprov);
|
||||
if (elprov)
|
||||
CHECK_EXPECT(prov_callback_base_hwnd);
|
||||
break;
|
||||
|
||||
return sa;
|
||||
case ProviderType_Proxy:
|
||||
if (Provider_proxy.hwnd == hwnd)
|
||||
elprov = proxy_prov;
|
||||
break;
|
||||
|
||||
case ProviderType_NonClientArea:
|
||||
if (hwnd == Provider_nc3.hwnd)
|
||||
elprov = &Provider_nc3.IRawElementProviderSimple_iface;
|
||||
else if (hwnd == Provider_nc2.hwnd)
|
||||
elprov = &Provider_nc2.IRawElementProviderSimple_iface;
|
||||
else if (hwnd == Provider_nc.hwnd)
|
||||
elprov = &Provider_nc.IRawElementProviderSimple_iface;
|
||||
|
||||
if (elprov)
|
||||
CHECK_EXPECT(prov_callback_nonclient);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return get_safearray_for_elprov(elprov);
|
||||
}
|
||||
|
||||
static void test_UiaRegisterProviderCallback(void)
|
||||
|
@ -10945,6 +11017,12 @@ static void set_provider_runtime_id(struct Provider *prov, int val, int val2)
|
|||
prov->runtime_id[1] = val2;
|
||||
}
|
||||
|
||||
static void set_provider_method_event_data(struct Provider *prov, HANDLE event_handle, int method_id)
|
||||
{
|
||||
prov->method_call_event_handle = event_handle;
|
||||
prov->method_call_event_method_id = method_id;
|
||||
}
|
||||
|
||||
static void initialize_provider_advise_events_ids(struct Provider *prov)
|
||||
{
|
||||
prov->advise_events_added_event_id = prov->advise_events_removed_event_id = 0;
|
||||
|
@ -10970,6 +11048,8 @@ static void initialize_provider(struct Provider *prov, int prov_opts, HWND hwnd,
|
|||
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));
|
||||
prov->method_call_event_handle = NULL;
|
||||
prov->method_call_event_method_id = -1;
|
||||
if (initialize_nav_links)
|
||||
{
|
||||
prov->frag_root = NULL;
|
||||
|
@ -14777,13 +14857,258 @@ static void test_IUIAutomationFocusChangedEventHandler(IUIAutomation *uia_iface)
|
|||
IUIAutomationElement_Release(elem);
|
||||
}
|
||||
|
||||
static void test_CUIAutomation_event_handlers(IUIAutomation *uia_iface)
|
||||
struct com_win_event_test_thread_data
|
||||
{
|
||||
IUIAutomation *uia_iface;
|
||||
HWND test_hwnd;
|
||||
HWND test_child_hwnd;
|
||||
};
|
||||
|
||||
static void test_uia_com_event_handler_event_advisement(IUIAutomation *uia_iface, HWND test_hwnd, HWND test_child_hwnd)
|
||||
{
|
||||
IUIAutomationElement *elem;
|
||||
HANDLE method_event[4];
|
||||
int event_handle_count;
|
||||
DWORD wait_res;
|
||||
BOOL is_win11;
|
||||
HRESULT hr;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(method_event); i++)
|
||||
method_event[i] = CreateEventW(NULL, FALSE, FALSE, NULL);
|
||||
|
||||
/* Only sends WM_GETOBJECT twice on Win11. */
|
||||
set_uia_hwnd_expects(0, 1, 1, 2, 0);
|
||||
hr = IUIAutomation_ElementFromHandle(uia_iface, test_hwnd, &elem);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
ok(!!elem, "elem == NULL\n");
|
||||
ok(Provider.ref >= 2, "Unexpected refcnt %ld\n", Provider.ref);
|
||||
ok(Provider_hwnd2.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd2.ref);
|
||||
ok(Provider_nc2.ref == 2, "Unexpected refcnt %ld\n", Provider_nc2.ref);
|
||||
check_uia_hwnd_expects_at_least(0, FALSE, 1, FALSE, 1, FALSE, 1, FALSE, 0, FALSE);
|
||||
|
||||
/*
|
||||
* The COM API has no equivalent to UiaEventAddWindow, which means all
|
||||
* event advisement has to be done by the COM API itself. It does this by
|
||||
* using EVENT_OBJECT_SHOW as a way to find HWNDs that need to be advised.
|
||||
*/
|
||||
set_uia_hwnd_expects(0, 1, 1, 4, 0); /* Only done on Win11. */
|
||||
hr = IUIAutomation_AddAutomationEventHandler(uia_iface, UIA_LiveRegionChangedEventId, elem, TreeScope_Subtree, NULL,
|
||||
&AutomationEventHandler.IUIAutomationEventHandler_iface);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
ok(AutomationEventHandler.ref > 1, "Unexpected refcnt %ld\n", AutomationEventHandler.ref);
|
||||
is_win11 = !!CALLED_COUNT(prov_callback_base_hwnd);
|
||||
check_uia_hwnd_expects_at_most(0, 1, 1, 4, 0);
|
||||
|
||||
set_provider_method_event_data(&Provider_hwnd2, method_event[0], ADVISE_EVENTS_EVENT_ADDED);
|
||||
set_provider_method_event_data(&Provider_nc2, method_event[1], ADVISE_EVENTS_EVENT_ADDED);
|
||||
set_provider_method_event_data(&Provider, method_event[2], ADVISE_EVENTS_EVENT_ADDED);
|
||||
event_handle_count = 3;
|
||||
|
||||
/*
|
||||
* Raise EVENT_OBJECT_SHOW on a non-visible HWND. Its providers will not
|
||||
* be advised of events being listened for.
|
||||
*/
|
||||
ok(!IsWindowVisible(test_hwnd), "Test HWND is visible\n");
|
||||
NotifyWinEvent(EVENT_OBJECT_SHOW, test_hwnd, OBJID_WINDOW, CHILDID_SELF);
|
||||
ok(msg_wait_for_all_events(method_event, event_handle_count, 500) == WAIT_TIMEOUT, "Wait for method_event(s) didn't timeout.\n");
|
||||
|
||||
/*
|
||||
* This fires off EVENT_OBJECT_SHOW, our providers will be advised of
|
||||
* events.
|
||||
*/
|
||||
initialize_provider_advise_events_ids(&Provider);
|
||||
initialize_provider_advise_events_ids(&Provider_nc2);
|
||||
initialize_provider_advise_events_ids(&Provider_hwnd2);
|
||||
|
||||
set_uia_hwnd_expects(0, 2, 2, 6, 0); /* Only done more than one of each on Win11. */
|
||||
ShowWindow(test_hwnd, SW_SHOW);
|
||||
wait_res = msg_wait_for_all_events(method_event, event_handle_count, 3000);
|
||||
if ((wait_res == WAIT_TIMEOUT) && (Provider_nc2.advise_events_added_event_id && Provider_hwnd2.advise_events_added_event_id) &&
|
||||
!Provider.advise_events_added_event_id)
|
||||
{
|
||||
/*
|
||||
* Windows 7 won't advise a nested node provider from the current
|
||||
* process of events being listened for.
|
||||
*/
|
||||
win_skip("Windows 7 only advises clientside providers of events, skipping further tests.\n");
|
||||
hr = IUIAutomation_RemoveAutomationEventHandler(uia_iface, UIA_LiveRegionChangedEventId, elem,
|
||||
&AutomationEventHandler.IUIAutomationEventHandler_iface);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
ok(AutomationEventHandler.ref == 1, "Unexpected refcnt %ld\n", AutomationEventHandler.ref);
|
||||
IUIAutomationElement_Release(elem);
|
||||
|
||||
set_provider_method_event_data(&Provider_hwnd2, NULL, -1);
|
||||
set_provider_method_event_data(&Provider_nc2, NULL, -1);
|
||||
set_provider_method_event_data(&Provider, NULL, -1);
|
||||
goto exit;
|
||||
}
|
||||
todo_wine ok(wait_res != WAIT_TIMEOUT, "Wait for method_event(s) timed out.\n");
|
||||
check_uia_hwnd_expects_at_least(0, FALSE, 1, TRUE, 1, TRUE, 1, TRUE, 0, FALSE);
|
||||
|
||||
/*
|
||||
* Manually fire off EVENT_OBJECT_SHOW, providers will be advised of
|
||||
* events being added again.
|
||||
*/
|
||||
set_uia_hwnd_expects(0, 2, 2, 6, 0); /* Only done more than one of each on Win11. */
|
||||
NotifyWinEvent(EVENT_OBJECT_SHOW, test_hwnd, OBJID_WINDOW, CHILDID_SELF);
|
||||
todo_wine ok(msg_wait_for_all_events(method_event, event_handle_count, 3000) != WAIT_TIMEOUT, "Wait for method_event(s) timed out.\n");
|
||||
check_uia_hwnd_expects_at_least(0, FALSE, 1, TRUE, 1, TRUE, 1, TRUE, 0, FALSE);
|
||||
|
||||
/*
|
||||
* Providers are only advised of events being listened for if an event is
|
||||
* raised with an objid of OBJID_WINDOW.
|
||||
*/
|
||||
NotifyWinEvent(EVENT_OBJECT_SHOW, test_hwnd, OBJID_CLIENT, CHILDID_SELF);
|
||||
ok(msg_wait_for_all_events(method_event, event_handle_count, 500) == WAIT_TIMEOUT, "Wait for method_event(s) didn't timeout.\n");
|
||||
|
||||
set_provider_method_event_data(&Provider_hwnd2, NULL, -1);
|
||||
set_provider_method_event_data(&Provider_nc2, NULL, -1);
|
||||
set_provider_method_event_data(&Provider, NULL, -1);
|
||||
|
||||
/*
|
||||
* Show our child HWND. Navigation is done to confirm it is within the
|
||||
* scope of our event handler, and it is only advised if it is.
|
||||
*/
|
||||
set_provider_method_event_data(&Provider_hwnd3, method_event[0], ADVISE_EVENTS_EVENT_ADDED);
|
||||
set_provider_method_event_data(&Provider_nc3, method_event[1], ADVISE_EVENTS_EVENT_ADDED);
|
||||
set_provider_method_event_data(&Provider2, method_event[2], ADVISE_EVENTS_EVENT_ADDED);
|
||||
|
||||
SET_EXPECT_MULTI(child_winproc_GETOBJECT_UiaRoot, 6); /* Only done more than once on Win11. */
|
||||
set_uia_hwnd_expects(0, 2, 3, 5, 0); /* Only done more than one of each on Win11. */
|
||||
ShowWindow(test_child_hwnd, SW_SHOW);
|
||||
todo_wine ok(msg_wait_for_all_events(method_event, event_handle_count, 3000) != WAIT_TIMEOUT, "Wait for method_event(s) timed out.\n");
|
||||
check_uia_hwnd_expects_at_least(0, FALSE, 1, TRUE, 1, TRUE, 1, TRUE, 0, FALSE);
|
||||
todo_wine CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot);
|
||||
|
||||
/* Same deal as before, it will advise multiple times. */
|
||||
SET_EXPECT_MULTI(child_winproc_GETOBJECT_UiaRoot, 6); /* Only done more than once on Win11. */
|
||||
set_uia_hwnd_expects(0, 2, 3, 5, 0); /* Only done more than one of each on Win11. */
|
||||
NotifyWinEvent(EVENT_OBJECT_SHOW, test_child_hwnd, OBJID_WINDOW, CHILDID_SELF);
|
||||
todo_wine ok(msg_wait_for_all_events(method_event, event_handle_count, 3000) != WAIT_TIMEOUT, "Wait for method_event(s) timed out.\n");
|
||||
check_uia_hwnd_expects_at_least(0, FALSE, 1, TRUE, 1, TRUE, 1, TRUE, 0, FALSE);
|
||||
todo_wine CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot);
|
||||
|
||||
/* Break navigation chain, can't reach our test element so no advisement. */
|
||||
Provider_hwnd3.parent = NULL;
|
||||
SET_EXPECT_MULTI(child_winproc_GETOBJECT_UiaRoot, 2); /* Only done more than once on Win11. */
|
||||
set_uia_hwnd_expects(0, 1, 1, 1, 0);
|
||||
NotifyWinEvent(EVENT_OBJECT_SHOW, test_child_hwnd, OBJID_WINDOW, CHILDID_SELF);
|
||||
ok(msg_wait_for_all_events(method_event, event_handle_count, 2000) == WAIT_TIMEOUT, "Wait for method_event(s) didn't timeout.\n");
|
||||
check_uia_hwnd_expects(0, FALSE, 1, TRUE, 1, TRUE, 1, TRUE, 0, FALSE);
|
||||
todo_wine CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot);
|
||||
|
||||
set_provider_method_event_data(&Provider_hwnd3, NULL, -1);
|
||||
set_provider_method_event_data(&Provider_nc3, NULL, -1);
|
||||
set_provider_method_event_data(&Provider2, NULL, -1);
|
||||
|
||||
hr = IUIAutomation_RemoveAutomationEventHandler(uia_iface, UIA_LiveRegionChangedEventId, elem,
|
||||
&AutomationEventHandler.IUIAutomationEventHandler_iface);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
|
||||
IUIAutomationElement_Release(elem);
|
||||
|
||||
/*
|
||||
* Register event handler on desktop element with a scope of
|
||||
* TreeScope_Subtree. All EVENT_OBJECT_SHOW events will result in event
|
||||
* advisement regardless of navigation.
|
||||
*/
|
||||
set_uia_hwnd_expects(0, 1, 1, 0, 0);
|
||||
hr = IUIAutomation_GetRootElement(uia_iface, &elem);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
check_uia_hwnd_expects(0, FALSE, 1, FALSE, 1, FALSE, 0, FALSE, 0, FALSE);
|
||||
|
||||
SET_EXPECT(child_winproc_GETOBJECT_UiaRoot); /* Only done on Win11. */
|
||||
set_uia_hwnd_expects(0, 2, 2, 3, 0); /* Only done on Win11. */
|
||||
hr = IUIAutomation_AddAutomationEventHandler(uia_iface, UIA_LiveRegionChangedEventId, elem, TreeScope_Subtree, NULL,
|
||||
&AutomationEventHandler.IUIAutomationEventHandler_iface);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
ok(AutomationEventHandler.ref > 1, "Unexpected refcnt %ld\n", AutomationEventHandler.ref);
|
||||
CHECK_CALLED_AT_MOST(child_winproc_GETOBJECT_UiaRoot, 1);
|
||||
check_uia_hwnd_expects_at_most(0, 2, 2, 3, 0);
|
||||
|
||||
set_provider_method_event_data(&Provider_hwnd, method_event[0], ADVISE_EVENTS_EVENT_ADDED);
|
||||
set_provider_method_event_data(&Provider_nc, method_event[1], ADVISE_EVENTS_EVENT_ADDED);
|
||||
set_provider_method_event_data(&Provider_proxy, method_event[2], ADVISE_EVENTS_EVENT_ADDED);
|
||||
|
||||
/*
|
||||
* Windows 11 always advises all HWNDs on the desktop, so we wait for our
|
||||
* child window provider to be advised as well.
|
||||
*/
|
||||
if (is_win11)
|
||||
{
|
||||
set_provider_method_event_data(&Provider2, method_event[3], ADVISE_EVENTS_EVENT_ADDED);
|
||||
event_handle_count++;
|
||||
}
|
||||
|
||||
SET_EXPECT(child_winproc_GETOBJECT_UiaRoot); /* Only done on Win11. */
|
||||
set_uia_hwnd_expects(0, 3, 3, 1, 0); /* Only done more than once on Win11. */
|
||||
NotifyWinEvent(EVENT_OBJECT_SHOW, GetDesktopWindow(), OBJID_WINDOW, CHILDID_SELF);
|
||||
todo_wine ok(msg_wait_for_all_events(method_event, event_handle_count, 2000) != WAIT_TIMEOUT, "Wait for method_event(s) timed out.\n");
|
||||
CHECK_CALLED_AT_MOST(winproc_GETOBJECT_UiaRoot, 1);
|
||||
CHECK_CALLED_AT_MOST(child_winproc_GETOBJECT_UiaRoot, 1);
|
||||
check_uia_hwnd_expects_at_least(0, FALSE, 1, TRUE, 1, TRUE, 0, FALSE, 0, FALSE);
|
||||
|
||||
set_provider_method_event_data(&Provider_hwnd, NULL, -1);
|
||||
set_provider_method_event_data(&Provider_nc, NULL, -1);
|
||||
set_provider_method_event_data(&Provider_proxy, NULL, -1);
|
||||
|
||||
/*
|
||||
* Test window isn't connected to desktop element through navigation, but
|
||||
* still gets advised of events on a desktop HWND event.
|
||||
*/
|
||||
set_provider_method_event_data(&Provider_hwnd2, method_event[0], ADVISE_EVENTS_EVENT_ADDED);
|
||||
set_provider_method_event_data(&Provider_nc2, method_event[1], ADVISE_EVENTS_EVENT_ADDED);
|
||||
set_provider_method_event_data(&Provider, method_event[2], ADVISE_EVENTS_EVENT_ADDED);
|
||||
SET_EXPECT(child_winproc_GETOBJECT_UiaRoot); /* Only done on Win11. */
|
||||
set_uia_hwnd_expects(0, 2, 2, 7, 0); /* Only done more than once on Win11. */
|
||||
NotifyWinEvent(EVENT_OBJECT_SHOW, test_hwnd, OBJID_WINDOW, CHILDID_SELF);
|
||||
todo_wine ok(msg_wait_for_all_events(method_event, event_handle_count, 2000) != WAIT_TIMEOUT, "Wait for method_event(s) timed out.\n");
|
||||
CHECK_CALLED_AT_MOST(child_winproc_GETOBJECT_UiaRoot, 1);
|
||||
check_uia_hwnd_expects_at_most(0, 2, 2, 7, 0);
|
||||
|
||||
hr = IUIAutomation_RemoveAutomationEventHandler(uia_iface, UIA_LiveRegionChangedEventId, elem,
|
||||
&AutomationEventHandler.IUIAutomationEventHandler_iface);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
|
||||
IUIAutomationElement_Release(elem);
|
||||
|
||||
set_provider_method_event_data(&Provider_hwnd2, NULL, -1);
|
||||
set_provider_method_event_data(&Provider_nc2, NULL, -1);
|
||||
set_provider_method_event_data(&Provider, NULL, -1);
|
||||
if (is_win11)
|
||||
set_provider_method_event_data(&Provider2, NULL, -1);
|
||||
|
||||
exit:
|
||||
for (i = 0; i < ARRAY_SIZE(method_event); i++)
|
||||
CloseHandle(method_event[i]);
|
||||
}
|
||||
|
||||
static DWORD WINAPI uia_com_event_handler_win_event_test_thread(LPVOID param)
|
||||
{
|
||||
struct com_win_event_test_thread_data *test_data = (struct com_win_event_test_thread_data *)param;
|
||||
IUIAutomation *uia_iface = test_data->uia_iface;
|
||||
|
||||
CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
||||
UiaRegisterProviderCallback(uia_com_win_event_clientside_provider_callback);
|
||||
|
||||
test_uia_com_event_handler_event_advisement(uia_iface, test_data->test_hwnd, test_data->test_child_hwnd);
|
||||
|
||||
UiaRegisterProviderCallback(NULL);
|
||||
CoUninitialize();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_CUIAutomation_event_handlers(IUIAutomation *uia_iface)
|
||||
{
|
||||
struct com_win_event_test_thread_data test_data = { uia_iface, NULL };
|
||||
IUIAutomationElement *elem;
|
||||
HANDLE thread;
|
||||
HRESULT hr;
|
||||
HWND hwnd;
|
||||
|
||||
ComEventData.event_hwnd = hwnd = create_test_hwnd("test_CUIAutomation_event_handlers class");
|
||||
test_data.test_hwnd = ComEventData.event_hwnd = hwnd = create_test_hwnd("test_CUIAutomation_event_handlers class");
|
||||
|
||||
/* Set up providers for the desktop window and our test HWND. */
|
||||
set_clientside_providers_for_hwnd(&Provider_proxy, &Provider_nc, &Provider_hwnd, GetDesktopWindow());
|
||||
|
@ -14810,11 +15135,48 @@ static void test_CUIAutomation_event_handlers(IUIAutomation *uia_iface)
|
|||
|
||||
test_IUIAutomationEventHandler(uia_iface, elem);
|
||||
test_IUIAutomationFocusChangedEventHandler(uia_iface);
|
||||
|
||||
IUIAutomationElement_Release(elem);
|
||||
|
||||
/* Create a test child window. */
|
||||
test_data.test_child_hwnd = create_child_test_hwnd("test_CUIAutomation_event_handlers child class", hwnd);
|
||||
set_clientside_providers_for_hwnd(NULL, &Provider_nc3, &Provider_hwnd3, test_data.test_child_hwnd);
|
||||
initialize_provider(&Provider2, ProviderOptions_ServerSideProvider, test_data.test_child_hwnd, TRUE);
|
||||
Provider2.frag_root = &Provider2.IRawElementProviderFragmentRoot_iface;
|
||||
Provider2.ignore_hwnd_prop = TRUE;
|
||||
Provider_hwnd3.parent = &Provider_hwnd2.IRawElementProviderFragment_iface;
|
||||
child_win_prov_root = &Provider2.IRawElementProviderSimple_iface;
|
||||
|
||||
hr = IUIAutomation_RemoveAllEventHandlers(uia_iface);
|
||||
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
|
||||
|
||||
/*
|
||||
* Particular versions of Windows 7 trigger access violations when doing
|
||||
* WinEvent tests, just skip them for Windows 7.
|
||||
*/
|
||||
if (!UiaLookupId(AutomationIdentifierType_Property, &OptimizeForVisualContent_Property_GUID))
|
||||
{
|
||||
win_skip("Skipping COM API WinEvent translation tests for Win7\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
thread = CreateThread(NULL, 0, uia_com_event_handler_win_event_test_thread, (void *)&test_data, 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);
|
||||
|
||||
exit:
|
||||
UiaRegisterProviderCallback(NULL);
|
||||
DestroyWindow(hwnd);
|
||||
UnregisterClassA("test_CUIAutomation_event_handlers class", NULL);
|
||||
UnregisterClassA("test_CUIAutomation_event_handlers child class", NULL);
|
||||
method_sequences_enabled = TRUE;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue